认识java虚拟机(3)

内存分配策略:

优先分配到eden

大对象直接分配到老年代

长期存活的对象分配到老年代

空间分配担保

动态对象年龄判断

1.优先分配到eden

-verbose:gc -XX:+PrintGCDetails  默认是Parallel Scavenge 收集器,标志为:PSYoungGen

-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC   指定Serial收集器  ,标志为:def new generation

public class Main {
	
	public static void main(String[] args) {
		byte [] m=new byte[4*1024*1024];
	}
}

代码中为byte数组分配了4M的空间,运行结果:大致分析

    新生代总计内存33M,使用了6M,eden区域 内存总计30M,21%的空间被使用,tenured generation养老区内存总计75M

更改代码如下:

public class Main {
	
	public static void main(String[] args) {
		byte [] m=new byte[40*1024*1024];
	}
}

运行发现:大对象被直接分配到了tenured generation,eden区域的使用内存减少

指定jvm参数:

-verbose:gc(-verbose:gc 是 -XX:+PrintGC的别名,打印gc运行信息)

-XX:+PrintGCDetails(详细打印jvm运行日志)

-XX:+UseSerialGC(指定serial GC垃圾回收器)

-Xms20M(设置JVM最大可用内存为20M)

-Xmx20M(用来设置程序初始化的时候内存栈的大小,增加这个值的话你的程序的启动性能会得到提高

                     此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存)

-Xmn10M(指定新生代内存10M)

-XX:SurvivorRatio=8 (指定新生代的eden为8M)

-XX:PretenureSizeThreshold=6M(指定6M以上的就判定为大对象,大对象直接分配到tenured区)

public class Main {
	
	public static void main(String[] args) {
		//m1,m2,m3被分配到了tenured区域 8.192M*58%=4M
		byte [] m1=new byte[2*1024*1024];
		byte [] m2=new byte[2*1024*1024];
		byte [] m3=new byte[2*1024*1024];
		//m4被分配到了eden区,10M*60%=6M
		byte [] m4=new byte[4*1024*1024];
		//调用gc垃圾回收,回收from space和to   space 垃圾区域所占的内存
		System.gc();
	}
}

[GC (Allocation Failure) [DefNew: 7129K->530K(9216K),] 7129K->6674K(19456K), 


<p>调用allocation gc,回收了eden的7M空间,6M的三个对象仍存活,故未被清理掉</p>

[Full GC (System.gc()) [Tenured: 6144K->6144K(10240K)] 10930K->10768K(19456K), [Metaspace: 2654K->2654K(1056768K)]

<h1>调用full gc,清理掉from space的1M垃圾空间</h1>
Heap
 def new generation   total 9216K, used 4788K
  eden space 8192K,  58% used 
  from space 1024K,   0% used 
  to   space 1024K,   0% used 
 tenured generation   total 10240K, used 6144K 
   the space 10240K,  60% used
 Metaspace       used 2660K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 286K, capacity 386K, committed 512K, reserved 1048576K

长期存活的对象进入老年代

-XX:MaxTenuringThreshold 15

Age 1+1+1

空间分配担保:

-XX:+HandlePromotionFailure(先衡量有无足够的能力【空间】满足你的内存分配的需求,+是开启,-是禁用,老年代的空间并不能容纳下所有的新生代的对象的空间)

逃逸分析与栈上分配

栈上分配:方法执行需要创建一个栈帧,方法执行,栈帧进栈出栈,栈区域是根据方法的执行来进行分配与释放,不需要垃圾回收器来处理,性能很高

为逃逸的对象的可在栈上进行分配,分析出对象的作用域(方法体内部,方法内有效,它为逃逸,故可分配在栈上)

逃逸分析的情况:

public class StackAllocation {
	 public StackAllocation obj;
	/* 方法返回StackAllocation对象,放生逃逸*/
    public StackAllocation getInstance() {
    	return obj==null?new StackAllocation():obj;
    }
	/* 为成员属性赋值,放生逃逸*/
	 public void setObj() {
		 this.obj=new StackAllocation();
	 }
	 
	/* 对象的作用域仅在当前方法中有效,没有发生逃逸*/
	 public void useStackAllcation() {
		 /*在方法中定义对象,则对象会被直接分配到栈中,随着方法结束,栈内存就会被移出,内存回收,对象也随之销毁,性能较高
		 能局部创建对象,就局部创建对象*/
		 StackAllocation s =new StackAllocation();
	 }
	/* 引用成员变量的值,发生逃逸*/
	 public void useStackAllocation2() {
		 StackAllocation s=getInstance();
	 }
}

猜你喜欢

转载自blog.csdn.net/qq_41063141/article/details/86087482
今日推荐