การใช้งานหน่วยความจำ Python ของอาร์เรย์ที่ไม่ระบุ


156

ฉันใช้หลามเพื่อวิเคราะห์ไฟล์ขนาดใหญ่และฉันพบปัญหาเรื่องหน่วยความจำดังนั้นฉันจึงใช้ sys.getsizeof () เพื่อพยายามติดตามการใช้งาน แต่พฤติกรรมของอาร์เรย์ numpy นั้นเป็นเรื่องที่แปลกประหลาด นี่คือตัวอย่างที่เกี่ยวข้องกับแผนที่ของอัลเบียนที่ฉันต้องเปิด:

>>> import numpy as np
>>> import struct
>>> from sys import getsizeof
>>> f = open('Albedo_map.assoc', 'rb')
>>> getsizeof(f)
144
>>> albedo = struct.unpack('%df' % (7200*3600), f.read(7200*3600*4))
>>> getsizeof(albedo)
207360056
>>> albedo = np.array(albedo).reshape(3600,7200)
>>> getsizeof(albedo)
80

ยังมีข้อมูลอยู่ แต่ขนาดของวัตถุซึ่งเป็นแผนที่ 3600x7200 พิกเซลได้หายไปจาก ~ 200 Mb ถึง 80 bytes ฉันหวังว่าปัญหาหน่วยความจำของฉันจะจบลงและเพียงแค่แปลงทุกอย่างให้เป็นอาร์เรย์ที่มีจำนวนมาก แต่ฉันรู้สึกว่าพฤติกรรมนี้ถ้าเป็นจริงจะเป็นการละเมิดกฎหมายของทฤษฎีข้อมูลหรืออุณหพลศาสตร์หรือบางอย่างดังนั้น มีแนวโน้มที่จะเชื่อว่า getizeof () ไม่ทำงานกับอาร์เรย์ที่มีค่ามาก ความคิดใด ๆ


8
จากเอกสารบนsys.getsizeof: "ส่งคืนขนาดของวัตถุเป็นไบต์วัตถุสามารถเป็นวัตถุชนิดใดก็ได้วัตถุในตัวทั้งหมดจะส่งคืนผลลัพธ์ที่ถูกต้อง แต่ไม่ต้องถือเป็นจริงสำหรับส่วนขยายของบุคคลที่สาม มีการใช้งานเฉพาะหน่วยความจำที่ประกอบโดยตรงกับวัตถุเท่านั้นที่จะถูกนำมาใช้
Joel Cornett

1
สิ่งนี้ทำให้getsizeofตัวบ่งชี้ที่ไม่น่าเชื่อถือของการใช้หน่วยความจำโดยเฉพาะอย่างยิ่งสำหรับส่วนขยายของบุคคลที่สาม
Joel Cornett

13
โดยทั่วไปปัญหาที่นี่resizeคือการส่งคืนviewไม่ใช่อาร์เรย์ใหม่ คุณได้ขนาดของมุมมองไม่ใช่ข้อมูลจริง
mgilson

ด้วยเหตุนี้sys.getsizeof(albedo.base)จะทำให้ขนาดของมุมมองที่ไม่ใช่
Eric

คำตอบ:


236

คุณสามารถใช้array.nbytesสำหรับอาร์เรย์ numpy เช่น:

>>> import numpy as np
>>> from sys import getsizeof
>>> a = [0] * 1024
>>> b = np.array(a)
>>> getsizeof(a)
8264
>>> b.nbytes
8192

มัน sys.getsizeof (a) หลังจากทำ sys นำเข้า
eddys

2
b.__sizeof__()เทียบเท่ากับsys.getsizeof(b)
palash

1
round(getsizeof(a) / 1024 / 1024,2)เพื่อรับ MB
gies0r

13

ฟิลด์nbytesจะให้ขนาดเป็นไบต์ขององค์ประกอบทั้งหมดของอาร์เรย์ใน a numpy.array:

size_in_bytes = my_numpy_array.nbytes

โปรดสังเกตว่าสิ่งนี้ไม่ได้วัด "แอตทริบิวต์ที่ไม่ใช่องค์ประกอบของวัตถุอาร์เรย์" ดังนั้นขนาดจริงในหน่วยไบต์อาจมีขนาดใหญ่กว่านี้สองสามไบต์


คำตอบนี้ยังคงสร้างอาร์เรย์ดังนั้นฉันคิดว่าคุณหมายถึง "โดยไม่จำเป็นต้องแปลงจากรายการเป็นอาร์เรย์" แม้ว่ามันจะเป็นความจริงที่คำตอบของ GWW สร้างรายการก่อนแล้วจึงแปลงเป็นอาเรย์นั่นคือข้างจุดเนื่องจาก OP มีอาเรย์อยู่แล้ว ... จุดคือวิธีการรับขนาดของอาเรมนัม สำคัญอย่างยิ่งว่าคุณจะได้รับอาเรย์ตั้งแต่แรก เราสามารถวิพากษ์วิจารณ์คำตอบนี้ในทำนองเดียวกันโดยบอกว่ามันช่วยปรับแต่งอาร์เรย์ที่มีอยู่เดิม
Moot

สวัสดี @Moot ขอบคุณสำหรับความคิดเห็น คำถามคือเกี่ยวกับวิธีการรับขนาดเป็นไบต์ของอาร์เรย์ ในขณะที่เป็นจริงว่าตัวอย่างของฉันแรกสร้างอาร์เรย์มันเป็นเพียงเพื่อวัตถุประสงค์ในการมีตัวอย่างที่สมบูรณ์ที่สามารถดำเนินการได้ ฉันจะแก้ไขคำตอบของฉันเพื่อเน้นสิ่งนี้
El Marce

1

ในโน๊ตบุ๊คหลามฉันมักจะต้องการที่จะกรองออก 'ห้อย' numpy.ndarray's โดยเฉพาะอย่างยิ่งคนที่ถูกเก็บไว้ใน_1, _2ฯลฯ ที่ไม่เคยมีความหมายมากที่จะมีชีวิตอยู่

ฉันใช้รหัสนี้เพื่อรับรายชื่อทั้งหมดและขนาดของมัน

ไม่แน่ใจว่าดีกว่าlocals()หรือglobals()ไม่

import sys
import numpy
from humanize import naturalsize

for size, name in sorted(
    (value.nbytes, name)
    for name, value in locals().items()
    if isinstance(value, numpy.ndarray)):
  print("{:>30}: {:>8}".format(name, naturalsize(size)))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.