Yanıtlar:
Mindprod , bunun cevaplanması kolay bir soru olmadığını belirtiyor:
Bir JVM, verileri ilkel olarak resmi boyutlara sahip gibi davranmak zorunda olsa da, herhangi bir miktarda dolgu veya ek yük ile dahili, büyük veya küçük endiandan istediği şekilde depolamakta özgürdür.
Örneğin, JVM veya yerel derleyiciboolean[]
64 bit uzunluğunda bir aBitSet
. Program aynı cevapları verdiği sürece size söylemek zorunda değildir.
- Yığında bazı geçici Nesneler ayırabilir.
- Bazı değişkenleri veya yöntem çağrılarını tamamen sabit olarak değiştirerek varlığını tamamen optimize edebilir.
- Her biri belirli bir durum için optimize edilmiş yöntemlerin veya döngülerin sürümlerini, yani bir yöntemin iki sürümünü derleyebilir, sonra hangisini çağıracağınıza karar verebilir.
Daha sonra elbette donanım ve işletim sistemi, yonga önbellek, SRAM önbellek, DRAM önbellek, sıradan RAM çalışma seti ve diskte yedekleme deposu üzerinde çok katmanlı önbelleklere sahiptir. Verileriniz her önbellek düzeyinde çoğaltılabilir. Tüm bu karmaşıklık RAM tüketimini ancak çok kabaca tahmin edebileceğiniz anlamına gelir.
Instrumentation.getObjectSize()
Bir nesne tarafından tüketilen depolama alanı tahminini elde etmek için kullanabilirsiniz .
Gerçek nesne düzenini, kapladığı alanı ve referansları görselleştirmek için JOL (Java Nesne Düzeni) aracını kullanabilirsiniz .
Modern bir 64 bit JDK'da, bir nesnenin 8 baytın katlarına doldurulmuş 12 baytlık bir başlığı vardır, bu nedenle minimum nesne boyutu 16 bayttır. 32 bit JVM'ler için ek yük 8 bayttır ve 4 baytın katlarına doldurulur. ( Dmitry Spikhalskiy'nin cevabından , Jayen'in cevabından ve JavaWorld'den .)
Tipik olarak, referanslar 32 bit platformlarda veya 64 bit platformlarda 4 bayttır -Xmx32G
; ve 32Gb ( -Xmx32G
) üzerinde 8 bayt . ( Sıkıştırılmış nesne referanslarına bakın .)
Sonuç olarak, 64 bit JVM tipik olarak% 30-50 daha fazla yığın alanı gerektirir. ( 32 veya 64 bit JVM kullanmalı mıyım?, 2012, JDK 1.7)
Kutulu sarmalayıcılar, ilkel türlere ( JavaWorld'den ) göre ek yüke sahiptir :
Integer
: 16 baytlık sonuç beklediğimden biraz daha kötü çünkü birint
değer sadece 4 ekstra bayta sığabiliyor. Bir kullanarakInteger
havai ben ilkel türü olarak değerini saklayabilir zaman kıyasla bana yüzde 300 bellek maliyeti
Long
: 16 bayt ayrıca: Yığındaki gerçek nesne boyutu, belirli bir CPU türü için belirli bir JVM uygulaması tarafından yapılan düşük düzeyli bellek hizalamasına tabidir. Görünüşe göre aLong
, 8 bayt Object ek yükü, artı gerçek uzun değer için 8 bayt daha fazla. Buna karşılık,Integer
kullanılmayan 4 baytlık bir delik vardı, çünkü JVM I, 8 baytlık bir kelime sınırında nesne hizalamasını zorlar.
Diğer konteynerler de pahalıdır:
Çok boyutlu diziler : başka bir sürpriz sunuyor.
Geliştiriciler genellikleint[dim1][dim2]
sayısal ve bilimsel hesaplama gibi yapılar kullanırlar .Bir
int[dim1][dim2]
dizi örneğinde, her iç içeint[dim2]
diziObject
kendi başına birdir. Her biri normal 16 baytlık dizi yükünü ekler. Üçgen veya düzensiz bir diziye ihtiyacım olmadığında, bu saf yükü temsil eder. Dizi boyutları büyük ölçüde farklı olduğunda etki büyür.Örneğin, bir
int[128][2]
örnek 3.600 bayt alır. Birint[256]
örneğin kullandığı (aynı kapasiteye sahip) 1.040 bayt ile karşılaştırıldığında , 3.600 bayt,% 246 ek yükü temsil eder. Aşırı durumdabyte[256][1]
, genel faktör neredeyse 19'dur! Bunu, aynı sözdiziminin herhangi bir depolama ek yükü eklemediği C / C ++ durumuyla karşılaştırın.
String
:String
a'nın bellek büyümesi dahili karakter dizisinin büyümesini izler. Ancak,String
sınıf 24 baytlık bir ek yük daha ekler.
String
10 karakter veya daha küçük bir boşluk için, faydalı yüke göre eklenen genel maliyet (her karakter için 2 bayt ve uzunluk için 4 bayt), yüzde 100 ila 400 arasındadır.
Şu örnek nesneyi düşünün :
class X { // 8 bytes for reference to the class definition
int a; // 4 bytes
byte b; // 1 byte
Integer c = new Integer(); // 4 bytes for a reference
}
Saf bir miktar, bir örneğinin X
17 bayt kullanacağını gösterir. Bununla birlikte, hizalama nedeniyle (dolgu olarak da adlandırılır), JVM belleği 8 baytın katları olarak ayırır, böylece 17 bayt yerine 24 bayt tahsis eder.
Bu mimari / jdk'ye bağlıdır. Modern bir JDK ve 64 bit mimarisi için, bir nesnenin 12 bayt üstbilgisi ve 8 bayt dolgusu vardır - bu nedenle minimum nesne boyutu 16 bayttır. Bir boyut belirlemek ve herhangi bir varlığın nesne düzeni ve iç yapısı hakkında ayrıntılar almak için Java Nesne Düzeni adlı bir araç kullanabilirsiniz veya bu bilgileri sınıf referansıyla tahmin edebilirsiniz. Ortamımda Tamsayı için çıktı örneği:
Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
java.lang.Integer object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 12 (object header) N/A
12 4 int Integer.value N/A
Instance size: 16 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
Bu nedenle, Tamsayı için örnek boyutu 16 bayttır, çünkü 4 bayt int üstbilgiden hemen sonra ve dolgu sınırından önce sıkıştırılmıştır.
Kod örneği:
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.util.VMSupport;
public static void main(String[] args) {
System.out.println(VMSupport.vmDetails());
System.out.println(ClassLayout.parseClass(Integer.class).toPrintable());
}
Javen kullanıyorsanız, JOL almak için:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.3.2</version>
</dependency>
Her nesnenin ilişkili monitör ve tür bilgileri ile alanların kendileri için belirli bir yükü vardır. Bunun ötesinde, alanlar hemen hemen düzenlenebilir, ancak JVM uygun görür (inanıyorum) - ancak başka bir cevapta gösterildiği gibi , en azından bazı JVM'ler oldukça sıkı bir şekilde paketlenecektir. Bunun gibi bir sınıf düşünün:
public class SingleByte
{
private byte b;
}
vs
public class OneHundredBytes
{
private byte b00, b01, ..., b99;
}
32 bitlik bir JVM'de 100 örnek SingleByte
1200 bayt almayı beklerdim (dolgu / hizalama nedeniyle alan için 8 bayt ek yük + 4 bayt). Bir örneğinin OneHundredBytes
108 bayt almasını beklerdim - tepegöz ve sonra 100 bayt paketlendi. Yine de JVM'ye göre değişebilir - bir uygulama, alanları paketlememeye karar verebilir OneHundredBytes
, bu da 408 bayt (= 8 bayt ek yükü + 4 * 100 hizalanmış / yastıklı bayt) almasına neden olabilir. 64 bit JVM'de ek yük de daha büyük olabilir (emin değilim).
DÜZENLEME: Aşağıdaki yoruma bakın; görünüşe göre HotSpot, 32 yerine 8 bayt sınırına ulaşır, bu nedenle her örneği SingleByte
16 bayt alır.
Her iki durumda da, "tek büyük nesne" en azından birden fazla küçük nesne kadar verimli olacaktır - bunun gibi basit durumlar için.
Bir programın toplam kullanılan / boş belleği programda
java.lang.Runtime.getRuntime();
Çalışma zamanının bellekle ilgili çeşitli yöntemleri vardır. Aşağıdaki kodlama örneği kullanımını göstermektedir.
package test;
import java.util.ArrayList;
import java.util.List;
public class PerformanceTest {
private static final long MEGABYTE = 1024L * 1024L;
public static long bytesToMegabytes(long bytes) {
return bytes / MEGABYTE;
}
public static void main(String[] args) {
// I assume you will know how to create a object Person yourself...
List < Person > list = new ArrayList < Person > ();
for (int i = 0; i <= 100000; i++) {
list.add(new Person("Jim", "Knopf"));
}
// Get the Java runtime
Runtime runtime = Runtime.getRuntime();
// Run the garbage collector
runtime.gc();
// Calculate the used memory
long memory = runtime.totalMemory() - runtime.freeMemory();
System.out.println("Used memory is bytes: " + memory);
System.out.println("Used memory is megabytes: " + bytesToMegabytes(memory));
}
}
Her nesnenin 32 bit sistemlerde (ve 64 bit sistemlerde 24 bayt) 16 baytlık bir ek yükü olduğu görülmektedir.
http://algs4.cs.princeton.edu/14analysis/ iyi bir bilgi kaynağıdır. Çok iyi olanlardan bir örnek aşağıdadır.
http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf de çok bilgilendiricidir, örneğin:
100 özniteliğe sahip bir nesne tarafından tüketilen bellek alanı, her biri bir özniteliğe sahip 100 nesneninkiyle aynı mıdır?
Hayır.
Bir nesne için ne kadar bellek ayrılmıştır?
Bir özellik eklerken ne kadar ek alan kullanılır?
Soru çok geniş olacak.
Sınıf değişkenine bağlıdır veya java'da bellek kullanımını bildirebilirsiniz.
Ayrıca, üstbilgiler ve referanslar için bazı ek bellek gereksinimleri vardır.
Bir Java nesnesi tarafından kullanılan yığın belleği şunları içerir:
ilkel alanlar için boyutlarına göre bellek (ilkel tiplerin boyutları için aşağıya bakınız);
referans alanları için bellek (her biri 4 bayt);
birkaç byte "temizlik" bilgisinden oluşan bir nesne başlığı;
Java'daki nesneler ayrıca, bir nesnenin sınıfını, kimliğini ve nesnenin o anda erişilebilir olup olmadığını, şu anda senkronizasyon kilitli olup olmadığını gibi durum bayraklarını kaydetme gibi bazı "temizlik" bilgileri gerektirir.
Java nesnesi başlık boyutu 32 ve 64 bit jvm'ye göre değişir.
Bunlar ana bellek tüketicileri jvm olmasına rağmen, bazen kodun hizalanması vb. Gibi ek alanlar gerektirir.
İlkel tiplerin boyutları
boole ve bayt - 1
karakter ve kısa - 2
int ve şamandıra - 4
uzun ve çift - 8
Java.lang.instrument.Istumentation yaklaşımından başka bir cevapta çok iyi sonuçlar aldım . Kullanımıyla ilgili iyi örnekler için Java Uzmanlarının Haber Bülteni'nden Enstrümantasyon Bellek Sayacı girişine ve SourceForge'daki java.sizeOf kütüphanesine bakın.
Herkes için yararlı olması durumunda, web sitemden bir nesnenin bellek kullanımını sorgulamak için küçük bir Java aracısı indirebilirsiniz . "Derin" bellek kullanımını da sorgulamanızı sağlar.
(String, Integer)
Guava Cache'nin öğe başına ne kadar bellek kullandığına dair kabaca bir tahmin elde etmek için harika çalıştı . Teşekkürler!
Ne kadar bellek tüketildiğine ilişkin kurallar JVM uygulamasına ve CPU mimarisine bağlıdır (örneğin 32 bit - 64 bit).
SUN JVM ile ilgili ayrıntılı kurallar için eski bloguma bak
Saygılarımızla, Markus