国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

jvm對象創(chuàng)建和內(nèi)存分配優(yōu)化

這篇具有很好參考價值的文章主要介紹了jvm對象創(chuàng)建和內(nèi)存分配優(yōu)化。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、創(chuàng)建對象過程

jvm對象創(chuàng)建和內(nèi)存分配優(yōu)化,jvm,jvm

1、類加載檢測

虛擬機遇到一條new指令時,首先將去檢查這個指令的參數(shù)是否能在常量池中定位到一個類的符號引用,并且檢查這個符號引用代表的類是否是否已被加載、解析和初始化過。如果沒有,那必須先執(zhí)行相應(yīng)的類加載過程。

new指令對應(yīng)語言層面講是,new關(guān)鍵字、對象克隆、對象序列化等

2、分配內(nèi)存

確保類加載完成之后,接下來jvm就需要為新生對象分配內(nèi)存。對象所需內(nèi)存的大小其實在類加載完成之后就可以確定了,然后就是從堆空間中劃分出一塊確定大小的內(nèi)存給該對象使用

對象內(nèi)存分配涉及到兩個問題:如何劃分內(nèi)存和如何控制并發(fā)分配內(nèi)存

劃分內(nèi)存的方法:

  • 指針碰撞(Bump the Pointer)(默認用指針碰撞):在堆中分配內(nèi)存中,有一個指針作為對象已分配和為分配內(nèi)存分界點,當對象分配進來,指針往未分配內(nèi)存區(qū)域挪動該對象相同大小的距離,這個過程叫指針碰撞
  • 空閑列表:(Free List):在堆中分配對象中,如果堆內(nèi)存的對象已分配區(qū)和未分配區(qū)特別凌亂,不是那么規(guī)整,這時候只能在jvm內(nèi)部維護一個列表去記錄哪些是內(nèi)存區(qū)域是可用的,當有對象分配進來就更新這個列表

解決并發(fā)問題的方法:

  • CAS(Compare And Swap):jvm內(nèi)部采用CAS自旋來保證對象一定會被分配到內(nèi)存
  • 本地線程分配緩沖(Thread Local Allocation Buffer, TLAB):每個線程在堆中預(yù)先分配一小塊內(nèi)存。通過-XX:+/-UseTLAB參數(shù)來設(shè)定虛擬機是否使用TLAB(JVM默認開啟-XX:+UseTLAB),-XX:TLABSize指定TLAB大小

3、初始化

內(nèi)存分配完成之后,虛擬機需要將分配到內(nèi)存空間的對象成員變量都初始化為零值(不包括對象頭),如果是TLAB,這一工作過程也可以提前至TLAB分配時進行。這一步操作保證了對象的實例字段在java代碼中可以不賦初始值就直接使用,程序能訪問到這些字段的數(shù)據(jù)類型所對應(yīng)的零值

4、設(shè)置對象頭

初始化零值后,jvm要對對象進行必要的設(shè)置,例如這個對象是哪個類的實例、如何才能找類的元數(shù)據(jù)信息、對象的哈希碼、對象的gc分帶年齡等信息。這些信息放在對象的對象頭Object Header之中

在HotSpot虛擬機中,對象在內(nèi)存中存儲的布局可分為三個區(qū)域:對象頭(Header)、示例數(shù)據(jù)(Instance Data)和對齊填充

  • 對象頭:比如hash碼,對象所屬分帶年齡、對象鎖、鎖狀態(tài)標志、偏向鎖(線程)ID、偏向時間,數(shù)組長度(數(shù)組對象才有)等
  • 實例數(shù)據(jù):存放類的屬性數(shù)據(jù)信息,包括父類的屬性信息
  • 對其填充:由于Hotspot虛擬機的自動內(nèi)存管理系統(tǒng)要求對象起始地址必須是8字節(jié)的整數(shù)倍,換句話說就是任何對象的大小都必須是8字節(jié)的整數(shù)倍。對象頭已被精心設(shè)計成正好是8的整數(shù)倍,因此,如果是對象實例數(shù)據(jù)沒有對齊的話,就需要通過對齊填充來補全

找了一張對象頭的圖片,

jvm對象創(chuàng)建和內(nèi)存分配優(yōu)化,jvm,jvm

5、執(zhí)行<init>方法

執(zhí)行<init>方法,即對象按照程序的意愿進行初始化,就是為屬性賦程序員指定值,然后執(zhí)行構(gòu)造方法。

6、對象的指針壓縮

引入查看對象大小的包:

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>
/**
 * 查看對象大小
 */
public class ObjectSizeTest {

    public static void main(String[] args) {
        // object對象16B
        // 對象頭
            // mark word 8B
            // Klass Pointer 4B
            // 不是數(shù)組 數(shù)組長度沒有
        // 實例數(shù)據(jù) 沒有成員變量
        // 對其填充 要求整個對象大小是8的整數(shù)倍 補上4B
        ClassLayout layout = ClassLayout.parseInstance(new Object());
        System.out.println(layout.toPrintable());

        System.out.println();
        // object對象16B
        // 對象頭
        // mark word 8B
        // Klass Pointer 4B
        // 數(shù)組長度占4B
        // 實例數(shù)據(jù) 沒有成員變量
        // 對其填充 要求整個對象大小是8的整數(shù)倍 不需要填充
        ClassLayout layout1 = ClassLayout.parseInstance(new int[]{});
        System.out.println(layout1.toPrintable());

        System.out.println();
        ClassLayout layout2 = ClassLayout.parseInstance(new A());
        System.out.println(layout2.toPrintable());
    }

    // -XX:+UseCompressedOops           默認開啟的壓縮所有指針
    // -XX:+UseCompressedClassPointers  默認開啟的壓縮對象頭里的類型指針Klass Pointer
    // Oops : Ordinary Object Pointers
    public static class A {
                        // 對象頭
                            // mark word 8B
                            // Klass Pointer 4B 如果關(guān)閉壓縮-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops,則占用8B
        int id;         // 4B
        String name;    // 對象在堆中的指針4B 如果關(guān)閉指針壓縮-XX:-UseCompressedOops,則占用8B
        byte b;         // 1B 這個有個內(nèi)部的填充3B
        Object o;       // 對象在堆中的指針4B 如果關(guān)閉指針壓縮-XX:-UseCompressedOops,則占用8B
                        // 需要對齊填充4B
                        // A對象大小為32B
    }
}

打印結(jié)果:

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total


[I object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     0    int [I.<elements>                             N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total


com.gaorufeng.jvm.ObjectSizeTest$A object internals:
 OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
      0     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                    (object header)                           61 cc 00 f8 (01100001 11001100 00000000 11111000) (-134165407)
     12     4                int A.id                                      0
     16     1               byte A.b                                       0
     17     3                    (alignment/padding gap)                  
     20     4   java.lang.String A.name                                    null
     24     4   java.lang.Object A.o                                       null
     28     4                    (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total

?什么是java對象的指針壓縮?

  1. jdk1.6 update14開始,在64bit操作系統(tǒng)中,jvm支持指針壓縮
  2. jvm配置參數(shù):UseCompressedOops,compressed--壓縮、oop(ordinary object pointer)--對象指針
  3. 啟動指針壓縮:-XX:+UseCompressedOops(默認開啟),禁止指針壓縮:-XX:UseCompressedOops

為什么要進行指針壓縮?

節(jié)省內(nèi)存空間,減少總線尋址性能上的消耗,堆內(nèi)存小于4G時,不需要啟用指針壓縮;堆內(nèi)存小于4G時,不需要啟用指針壓縮

二、對象的內(nèi)存分配

jvm對象創(chuàng)建和內(nèi)存分配優(yōu)化,jvm,jvm

1、棧上分配

棧上分配是為了減少gc的次數(shù),提高jvm性能,每次棧幀入棧時創(chuàng)建的對象,出棧就可以釋放內(nèi)存,對象自然就被清理了

需要開啟兩個參數(shù)來確定對象是否能在棧上分配

  • 對象逃逸分析:當一個對象在棧幀方法中,分析出沒有被外部對象引用到時,確定有可能在棧上分配,有引用到那就不能在棧上分配,逃逸分析參數(shù)(-XX:+DoEscapeAnalysis),jdk7之后默認開啟,關(guān)閉逃逸分析參數(shù)(-XX:-DoEscapeAnalysis)

舉個例子:

public User test1() {
		User user = new User();
		return user;
	}
	
	public void test2() {
		User user = new User();
	}

?test1()方法的對象的作用范圍是不確定的,test2()方法可以確定user對象作用范圍只在當前棧幀方法,不會逃逸出當前方法,可以在棧上進行分配

  • 標量替換:棧幀內(nèi)存區(qū)域的可用內(nèi)存不一定能夠存放一整個對象且隨機分布,開啟標量替換參數(shù)(-XX:+EliminateAllocations),jdk7之后默認開啟
  • 標量與聚合量:標量即不可被進一步分解的量,而Java的基本數(shù)據(jù)類型就是標量(如int、long等基本數(shù)據(jù)類型以及reference類型等),標量的對立就是可以被進一步分解的量,而這種量稱之為聚合量,而在Java中對象就是可以被進一步分解的聚合量

棧上分配依賴于逃逸分析和標量替換

棧上分配示例:
?

/**
 * 把堆空間設(shè)小一點 如果發(fā)生gc那就是分配在堆中,如果沒有g(shù)c就證明在棧上分配
 * 使用如下參數(shù)不會發(fā)生GC
 * -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:+EliminateAllocations
 * 使用如下參數(shù)都會發(fā)生大量GC
 * -Xmx15m -Xms15m -XX:-DoEscapeAnalysis -XX:+PrintGC -XX:+EliminateAllocations
 * -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-EliminateAllocations
 */
public class AllotOnStack {

	public static void allocation() {
		User user = new User();
	}
	
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000000; i++) {
			allocation();
		}
		long end = System.currentTimeMillis();
		System.out.println(end - start);
	}
}

2、堆中Eden區(qū)分配

大多數(shù)情況下,對象在新生代中Eden區(qū)分配。當Eden區(qū)沒有足夠內(nèi)存空間,虛擬機發(fā)起一次minor gc

  • minor gc/young gc:新生代垃圾對象的占用內(nèi)存回收
  • major gc/full gc:回收整個堆和方法區(qū)的垃圾對象占用的內(nèi)存,比minor gc慢10倍以上

新生代和老年代比例1:2,eden區(qū)和s0、s1區(qū)比例8:1:1

大部分對象都分配eden區(qū),eden區(qū)放滿了之后觸發(fā)minor gc,存活的對象放到survivor區(qū)中空的區(qū)域,下次觸發(fā)minor gc,繼續(xù)eden區(qū)和非空的survivor區(qū)的非垃圾對象往空的survivor區(qū)里面放

jvm默認有個參數(shù)-XX:+UseAdaptiveSizePolicy(默認開啟),會導(dǎo)致這個8:1:1比例自動變化,如果不想這個比例有變化可以設(shè)置參數(shù)-XX:-UseAdaptiveSizePolicy

示例:

/**
 * eden區(qū)大概默認65M
 * 添加運行JVM參數(shù): -XX:+PrintGCDetails
 */
public class GCTest {
	public static void main(String[] args) {
		 byte[] allocation1, allocation2/*, allocation3, allocation4, allocation5, allocation6*/;
	      allocation1 = new byte[62000*1024];

	      //allocation2 = new byte[8000*1024];

	      /*allocation3 = new byte[1000*1024];
	     allocation4 = new byte[1000*1024];
	     allocation5 = new byte[1000*1024];
	     allocation6 = new byte[1000*1024];*/
	}
}

運行結(jié)果:

Heap
 PSYoungGen      total 75776K, used 65024K [0x000000076bc00000, 0x0000000771080000, 0x00000007c0000000)
  eden space 65024K, 100% used [0x000000076bc00000,0x000000076fb80000,0x000000076fb80000)
  from space 10752K, 0% used [0x0000000770600000,0x0000000770600000,0x0000000771080000)
  to   space 10752K, 0% used [0x000000076fb80000,0x000000076fb80000,0x0000000770600000)
 ParOldGen       total 173568K, used 0K [0x00000006c3400000, 0x00000006cdd80000, 0x000000076bc00000)
  object space 173568K, 0% used [0x00000006c3400000,0x00000006c3400000,0x00000006cdd80000)
 Metaspace       used 2644K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 280K, capacity 386K, committed 512K, reserved 1048576K

?可以看到eden區(qū)被全部占用,繼續(xù)分配觸發(fā)minor gc,由于被引用是非垃圾對象,survivor區(qū)放不下,放到老年代

/**
 * eden區(qū)大概默認65M
 * 添加運行JVM參數(shù): -XX:+PrintGCDetails
 */
public class GCTest {
	public static void main(String[] args) {
		 byte[] allocation1, allocation2/*, allocation3, allocation4, allocation5, allocation6*/;
	      allocation1 = new byte[62000*1024];

	      allocation2 = new byte[8000*1024];

	      /*allocation3 = new byte[1000*1024];
	     allocation4 = new byte[1000*1024];
	     allocation5 = new byte[1000*1024];
	     allocation6 = new byte[1000*1024];*/
	}
}

打印結(jié)果:

[GC (Allocation Failure) [PSYoungGen: 64601K->632K(75776K)] 64601K->62640K(249344K), 0.0270385 secs] [Times: user=0.09 sys=0.02, real=0.03 secs] 
Heap
 PSYoungGen      total 75776K, used 9282K [0x000000076bc00000, 0x0000000775000000, 0x00000007c0000000)
  eden space 65024K, 13% used [0x000000076bc00000,0x000000076c472a78,0x000000076fb80000)
  from space 10752K, 5% used [0x000000076fb80000,0x000000076fc1e030,0x0000000770600000)
  to   space 10752K, 0% used [0x0000000774580000,0x0000000774580000,0x0000000775000000)
 ParOldGen       total 173568K, used 62008K [0x00000006c3400000, 0x00000006cdd80000, 0x000000076bc00000)
  object space 173568K, 35% used [0x00000006c3400000,0x00000006c708e010,0x00000006cdd80000)
 Metaspace       used 2644K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 280K, capacity 386K, committed 512K, reserved 1048576K

后面有對象來會繼續(xù)分配在eden區(qū)

/**
 * eden區(qū)大概默認65M
 * 添加運行JVM參數(shù): -XX:+PrintGCDetails
 */
public class GCTest {
	public static void main(String[] args) {
		 byte[] allocation1, allocation2, allocation3, allocation4, allocation5, allocation6;
	      allocation1 = new byte[62000*1024];

	      allocation2 = new byte[8000*1024];

	     allocation3 = new byte[1000*1024];
	     allocation4 = new byte[1000*1024];
	     allocation5 = new byte[1000*1024];
	     allocation6 = new byte[1000*1024];
	}
}

打印結(jié)果:

[GC (Allocation Failure) [PSYoungGen: 64601K->696K(75776K)] 64601K->62704K(249344K), 0.0411987 secs] [Times: user=0.06 sys=0.03, real=0.04 secs] 
Heap
 PSYoungGen      total 75776K, used 13621K [0x000000076bc00000, 0x0000000775000000, 0x00000007c0000000)
  eden space 65024K, 19% used [0x000000076bc00000,0x000000076c89f3d8,0x000000076fb80000)
  from space 10752K, 6% used [0x000000076fb80000,0x000000076fc2e030,0x0000000770600000)
  to   space 10752K, 0% used [0x0000000774580000,0x0000000774580000,0x0000000775000000)
 ParOldGen       total 173568K, used 62008K [0x00000006c3400000, 0x00000006cdd80000, 0x000000076bc00000)
  object space 173568K, 35% used [0x00000006c3400000,0x00000006c708e010,0x00000006cdd80000)
 Metaspace       used 2644K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 280K, capacity 386K, committed 512K, reserved 1048576K

3、大對象直接進入老年代

大對象就是需要大量連續(xù)內(nèi)存空間的對象(比如數(shù)組、字符串)。jvm參數(shù)-XX:PretenureSizeThreshold可以設(shè)置大對象的大小,如果對象超過設(shè)置大小會直接進入老年代,不會進入年輕代,這個參數(shù)只在Serial和ParNew兩個收集器下有效

比如設(shè)置jvm參數(shù):-XX:PretenureSizeThreshold=1000000 (單位是字節(jié)) -XX:+UseSerialGC,再執(zhí)行下上面的第一個程序就會發(fā)現(xiàn)大對象直接入老年代

/**
 * eden區(qū)大概默認65M
 * 添加運行JVM參數(shù): -XX:+PrintGCDetails -XX:PretenureSizeThreshold=1000000 -XX:+UseSerialGC
 */
public class GCTest {
	public static void main(String[] args) {
		// 6M的對象 設(shè)置1M就是大對象-XX:PretenureSizeThreshold=1000000
		byte[] allocation1 = allocation1 = new byte[6000*1024];
	}
}

打印結(jié)果(eden區(qū)默認會占用一定空間):

Heap
 def new generation   total 78016K, used 4162K [0x00000006c3400000, 0x00000006c88a0000, 0x0000000717800000)
  eden space 69376K,   6% used [0x00000006c3400000, 0x00000006c3810bd0, 0x00000006c77c0000)
  from space 8640K,   0% used [0x00000006c77c0000, 0x00000006c77c0000, 0x00000006c8030000)
  to   space 8640K,   0% used [0x00000006c8030000, 0x00000006c8030000, 0x00000006c88a0000)
 tenured generation   total 173440K, used 6000K [0x0000000717800000, 0x0000000722160000, 0x00000007c0000000)
   the space 173440K,   3% used [0x0000000717800000, 0x0000000717ddc010, 0x0000000717ddc200, 0x0000000722160000)
 Metaspace       used 2644K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 280K, capacity 386K, committed 512K, reserved 1048576K

為什么要這樣?

年輕代的minor gc是比較頻繁的,復(fù)制耗費性能

4、長期存活的對象進入老年代

對象的對象頭分帶年齡占4個字節(jié)(1111),換算成十進制就是15,所以分帶年齡不可能超過15.如果對象在eden區(qū)分配并且已經(jīng)經(jīng)歷過一次minor gc后仍然能夠存活,并且能被survivor區(qū)所容納,該對象將被移動到survivor區(qū),并將對象的年齡設(shè)為1。對象在survivor區(qū)每經(jīng)歷一次minor gc,年齡就會加1,當年齡增加到一定程度(默認15,CMS收集器默認6,不同的垃圾收集器會略微有點不同),就會被晉升到老年代中,對象晉升到老年代的年齡閾值,可以通過參數(shù)-XX:MaxTenuringThreshold來設(shè)置

5、對象動態(tài)年齡判斷機制

當前對象的survivor區(qū)域里(其中一塊區(qū)域,放對象的那快s區(qū)),一批對象的總大小大于這塊survivor區(qū)域的50%(-XX:TargetSurvivorRatio可以指定),那么此時大于等于這批對象年齡最大值的對象,就可以直接進入老年代了,例如survivor區(qū)域里現(xiàn)在有一批對象,年齡1+年齡2+年齡n的多個年齡對象總和超過survivor區(qū)域的50%,此時就會把n(含)以上的對象都放入老年代。這個規(guī)則其實是希望那些可能是長期存活的對象,盡早進入老年代。對象動態(tài)年齡判斷機制一般是在minor gc之后觸發(fā)

6、老年帶空間分配擔保機制

年輕代每次minor gc之前jvm都會計算下老年代剩余可用空間,如果這個可用空間小于年輕代里現(xiàn)有的所有對象大小之和(包括垃圾對象),就會看一個-XX:-HandlePromotionFailure(jdk1.8默認就設(shè)置了)的參數(shù)是否設(shè)置了,如果有這個參數(shù),就會看看老年代的可用內(nèi)存大小,是否大于之前每一次minor gc后進入老年代的對象的平均大小。如果上一步結(jié)果是小于或者之前說的參數(shù)沒有設(shè)置,那么就會觸發(fā)一次full gc,對老年代和年輕代一起回收一次垃圾,如果回收完還是沒有足夠空間存放新的對象就會發(fā)生OOM,如果minor gc之后剩余存活的需要挪到老年代的對象大小還是大于老年代可用空間,那么也會觸發(fā)full gc,full gc完之后如果還沒有空間放minor gc之后存活的對象,也會發(fā)生OOM

jvm對象創(chuàng)建和內(nèi)存分配優(yōu)化,jvm,jvm

三、內(nèi)存回收

1、引用計數(shù)法

此算法就是當一個對象被引用一次計數(shù)器就會加1,引用為0,則認為是可回收垃圾;唯一的問題就是如果是循環(huán)引用,那就永遠不可能為0,這樣會導(dǎo)致內(nèi)存泄露

2、可達性分析算法

從GC Roots(線程棧的本地變量、靜態(tài)變量、本地方法棧的變量等)開始往下找,找被GC Roots引用的對象,這些對象都是非垃圾對象

3、常見引用類型

  • 強引用:普通變量的引用
public static User user = new User();
  • 軟引用:一般情況下不會被回收,當發(fā)生gc釋放不出來空間了就會被回收;比如對象頻繁的創(chuàng)建但又不是特別重要的對象,可用用與大屏展示,可有可無的對象
public static SoftReference<User> user = new SoftReference<User>(new User());
  • 弱引用:弱引用跟沒引用一樣,會直接被回收,很少用
public static WeakReference user = new WeakReference(new User());
  • 虛引用:也稱為幽靈引用或者幻影引用,它是最弱的一種引用關(guān)系,幾乎不用

4、finalize()方法自救

每個對象都會執(zhí)行一次finalize()方法,在回收之前都會進行標記

  1. 第一次標記:查看是否有重寫finalize()方法,如果沒有就直接被回收掉了
  2. 第二次標記:執(zhí)行finalize()方法,這個時候如果為了不讓gc回收,可以讓對象與GC Roots關(guān)聯(lián)(這樣每次創(chuàng)建這個對象都會被自救,內(nèi)存泄漏,遲早會出現(xiàn)OOM)

5、方法區(qū)判斷無用的類

  1. 該類在堆中實例對象已被回收
  2. 加載該類的ClassLoader已被回收
  3. 該類的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法

6、內(nèi)存泄漏(會出現(xiàn)OOM)

程序內(nèi)部采用了靜態(tài)map緩存數(shù)據(jù),由于這個對象是靜態(tài)的,所以一直在old區(qū),隨著數(shù)據(jù)不斷增加,map占用內(nèi)存更大,會觸發(fā)full gc,但是清理之后map還是被引用,清理不掉,頻繁full耗費cpu和內(nèi)存(可以采用Ehcache對象淘汰結(jié)構(gòu)、LRU)

7、內(nèi)存溢出(會出現(xiàn)OOM)

新建的對象過大,導(dǎo)致內(nèi)存被占滿了文章來源地址http://www.zghlxwxcb.cn/news/detail-533817.html

到了這里,關(guān)于jvm對象創(chuàng)建和內(nèi)存分配優(yōu)化的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • JVM面試題-JVM對象的創(chuàng)建過程、內(nèi)存分配、內(nèi)存布局、訪問定位等問題詳解

    JVM面試題-JVM對象的創(chuàng)建過程、內(nèi)存分配、內(nèi)存布局、訪問定位等問題詳解

    內(nèi)存分配的兩種方式 指針碰撞 適用場合:堆內(nèi)存 規(guī)整 (即沒有內(nèi)存碎片)的情況下。 原理:用過的內(nèi)存全部整合到一邊,沒有用過的內(nèi)存放在另一邊,中間有一個分界指針,只需要向著沒用過的內(nèi)存方向?qū)⒃撝羔樢苿訉ο髢?nèi)存大小位置即可。 使用該分配方式的GC收集器:

    2024年02月08日
    瀏覽(21)
  • JVM 創(chuàng)建對象時分配內(nèi)存的幾種方法、分配方法的選擇

    ????????假設(shè)Java堆中內(nèi)存是絕對規(guī)整的,所有被使用過的內(nèi)存都被放在一邊,空閑的內(nèi)存被放在另一邊,中間放著一個指針作為分界點的指示器,那所分配內(nèi)存就僅僅是把那 個指針向空閑空間方向挪動一段與對象大小相等的距離。 ????????如果Java堆中的內(nèi)存并不是規(guī)

    2024年02月10日
    瀏覽(17)
  • Java進階(1)——JVM的內(nèi)存分配 & 反射Class類的類對象 & 創(chuàng)建對象的幾種方式 & 類加載(何時進入內(nèi)存JVM)& 注解 & 反射+注解的案例

    Java進階(1)——JVM的內(nèi)存分配 & 反射Class類的類對象 & 創(chuàng)建對象的幾種方式 & 類加載(何時進入內(nèi)存JVM)& 注解 & 反射+注解的案例

    1.java運行時的內(nèi)存分配,創(chuàng)建對象時內(nèi)存分配; 2.類加載的順序,創(chuàng)建一個唯一的類的類對象; 3.創(chuàng)建對象的方式,new,Class.forName,clone; 4.什么時候加載.class文件進入JVM內(nèi)存中,看到new,Class.forName; 5.如何加載?雙親委托(委派)機制:安全;AppClassLoader; 6.反射實質(zhì):能

    2024年02月14日
    瀏覽(32)
  • JVM 給對象分配內(nèi)存空間

    指針碰撞 空閑列表 TLAB 為對象分配空間的任務(wù)實際上便等同于把一塊確定大小的內(nèi)存塊從Java堆中劃分出來。 指針碰撞:(Bump The Pointer) 堆的內(nèi)存是絕對規(guī)整的,內(nèi)存主要分為兩部分,所有使用過的內(nèi)存被放在一邊,空閑的內(nèi)存被放在另一邊,中間放著一個指針作為分界點

    2024年02月11日
    瀏覽(20)
  • JVM對象在堆內(nèi)存中是否如何分配?

    JVM對象在堆內(nèi)存中是否如何分配?

    1:指針碰撞:內(nèi)存規(guī)整的情況下 2:空閑列表: 內(nèi)存不規(guī)整的情況下 選擇那種分配方式 是有 java堆是否規(guī)整而決定的。而java堆是否規(guī)整是否對應(yīng)的垃圾回收器是否帶有空間壓縮整理的能力決定的。 因此當使用Serial,ParNew等帶有壓縮整理過程的收集器時,系統(tǒng)采用的分配算法是

    2024年02月16日
    瀏覽(22)
  • JVM 垃圾回收詳解之內(nèi)存分配和回收原則+死亡對象判斷方法

    JVM 垃圾回收詳解之內(nèi)存分配和回收原則+死亡對象判斷方法

    當需要排查各種內(nèi)存溢出問題、當垃圾收集成為系統(tǒng)達到更高并發(fā)的瓶頸時,我們就需要對這些“自動化”的技術(shù)實施必要的監(jiān)控和調(diào)節(jié)。 Java 的自動內(nèi)存管理主要是針對對象內(nèi)存的回收和對象內(nèi)存的分配。同時,Java 自動內(nèi)存管理最核心的功能是 堆 內(nèi)存中對象的分配與回收

    2023年04月19日
    瀏覽(40)
  • JVM 內(nèi)存大對象監(jiān)控和優(yōu)化實踐

    JVM 內(nèi)存大對象監(jiān)控和優(yōu)化實踐

    作者:vivo 互聯(lián)網(wǎng)服務(wù)器團隊 - Liu Zhen、Ye Wenhao 服務(wù)器內(nèi)存問題是影響應(yīng)用程序性能和穩(wěn)定性的重要因素之一,需要及時排查和優(yōu)化。本文介紹了某核心服務(wù)內(nèi)存問題排查與解決過程。首先在JVM與大對象優(yōu)化上進行了有效的實踐,其次在故障轉(zhuǎn)移與大對象監(jiān)控上提出了可靠的

    2024年02月10日
    瀏覽(23)
  • 【Java虛擬機學習2】HotSpot虛擬機下對象的創(chuàng)建及在Java堆中對象的內(nèi)存分配、布局和對象的訪問

    【Java虛擬機學習2】HotSpot虛擬機下對象的創(chuàng)建及在Java堆中對象的內(nèi)存分配、布局和對象的訪問

    對象的生命周期主要分為創(chuàng)建、使用、銷毀這三大階段。從它被創(chuàng)建的一刻開始,到它被垃圾收集器(Garbage Collector)回收的一刻結(jié)束 對象的創(chuàng)建 。包括:1、類的加載 2、內(nèi)存的分配 3、初始化零值 4、設(shè)置對象頭 5、執(zhí)行init方法(具體操作步驟請看上述內(nèi)容,其中步驟1的類

    2024年02月16日
    瀏覽(21)
  • 【Android】使用對象池(Object Pool)來緩存已經(jīng)創(chuàng)建的字節(jié)數(shù)組,避免頻繁地進行內(nèi)存分配和回收操作提高性能

    在Android中,使用new byte[]創(chuàng)建字節(jié)數(shù)組是在堆上分配內(nèi)存,不會直接導(dǎo)致Native內(nèi)存的增長。但是,如果我們頻繁地創(chuàng)建和銷毀字節(jié)數(shù)組,就可能會導(dǎo)致堆內(nèi)存不足,并觸發(fā)GC,從而影響應(yīng)用程序的性能。 在Android中,堆內(nèi)存的大小是有限制的。如果我們頻繁地創(chuàng)建和銷毀字節(jié)數(shù)

    2024年02月09日
    瀏覽(29)
  • JVM的故事—— 內(nèi)存分配策略

    堆內(nèi)存有新生代和老年代,新生代中有一個Eden區(qū)和一個Survivor區(qū)(from space或者to space)。當有新的對象分配時,會優(yōu)先分配在Eden區(qū)。當Eden區(qū)空間不足分配給新對象時,會進行一次minor GC,回收完沒有引用的對象后,先考慮把一些Eden區(qū)的對象放到Survivor區(qū),如果放不下,就放到老

    2024年02月10日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包