赞
踩
注:本文参考学习周志明老师的《深入理解Java虚拟机(第3版)》
创建对象的过程
上面是详细的分析,现在做个简化
对象的组成
对象头的信息
接下来就是对象存储的实例数据。
对象的第三个部分是对齐填充。只是占位符的作用。要求对象的起始地址一定是8字节的整数倍。
Java程序通过栈上的reference数据来操作堆上的具体对象。他只是一个指向对象的引用。主流访问方式是句柄或者是直接指针
直接指针,Java堆的对象内存布局需要考虑到访问类型数据的相关信息,reference直接就是对象的地址。如果只是访问对象那么就不需要再间接访问一次。
//-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
public class MyTest {
static class OOMObject {
}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while (true) {
list.add(new OOMObject());
}
}
}
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid11304.hprof ...
Heap dump file created [28269066 bytes in 0.086 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
public class JavaVMStackSOF { private int stackLength = 1; public void stackLeak() { stackLength++; stackLeak(); } public static void main(String[] args) throws Throwable { JavaVMStackSOF oom = new JavaVMStackSOF(); try { oom.stackLeak(); } catch (Throwable e) { System.out.println("stack length:" + oom.stackLength); throw e; } } }
public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
// 使用Set保持着常量池引用,避免Full GC回收常量池行为
Set<String> set = new HashSet<String>();
// 在short范围内足以让6MB的PermSize产生OOM了
short i = 0;
while (true) {
set.add(String.valueOf(i++).intern());
}
}
}
String.intern的讨论
public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1);
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2);
}
}
GC Roots的对象
引用的拓展
CARD_TABLE [this address >> 9] = 0;
如何在对象赋值的时候更新维护卡表。
void oop_field_store(oop* field, oop new_value) {
// 引用字段赋值操作
*field = new_value;
// 写后屏障,在这里完成卡表状态更新
post_write_barrier(field, new_value);
}
总结
G1遇到的问题
Java堆分成多个独立Region之后,Region里面存在的跨代Region引用对象如何解决?
G1在并发标记过程如何与和用户线程互不干扰运行?
如何建立可靠的停顿预测模型?
G1的收集器的运行过程
初始标记:仅仅只是标记GC Roots能够直接关联的对象,并且修改TAMS指针的值。让下一个用户线程并发执行。能够正确在Region分配空间。需要停顿线程,但是耗时短,借助Minor GC的时候同步的。没有额外停顿
并发标记:从GC Roots开始对堆对象进行可达性分析。耗时长,能与用户线程并发进行。还需要记录STAB记录下的并发引用对象。
最终标记:对用户线程做一个暂停,处理STAB的重新标记。暂停用户线程
筛选回收:负责更新Region的统计消息,对Region的回收价值和成本进行排序。根据用户的期望停顿时间制定回收计划。选择任意多个Region回收。把存活的对象复制到空的Region,清理掉旧Region的空间。必须暂停用户线程。
也就是说G1除了并发阶段都是需要暂停线程的。在延迟可控的情况下必须保证高的吞吐量。兼顾延迟和吞吐量。
G1的优点
G1的弱点
G1的卡表更为复杂。可能会占用多内存的百分20。
内存占用很大。
CMS里面只需要给新生代创建卡表,老年代不需要,因为新生代的变化频繁,老年代创建卡表的问题就是新生代会不断地变化,维护卡表难度很大。但是G1就给每个Region创建了这样的卡表。
G1需要在指令执行的时候加上写后屏障解决卡表的维护,写前屏障解决实现原始快照的搜索算法的跟踪并发的指针变化。原始快照减少了并发标记和重新标记的消耗。避免了CMS的最终阶段停顿时间很长的问题。但是跟踪引用的变化也是需要负担的。G1对写屏障是一个异步操作,所以需要消息队列的结构把写前和写后屏障要做的事存放到队列,异步处理。
小内存上CMS更好,大内存上G1的表现更好。
垃圾收集器的衡量标准
Brooks Pointer的概念
转发指针的另外一个问题
Shenandoah的好处
内存布局
ZGC的核心问题并发整理算法的实现
染色指针的好处
ZGC的工作流程
对比
网站原本的服务器是32位操作系统。后来转换为16GB物理内存,操作系统为64位。原本只给堆分配了1.5GB。后来分配了12GB。
设置过大的内存给堆。但是内存仍然很快被用完。而且停顿时间很长
因为过大的堆内存会导致长时间的停顿。16GB内存尝试提升程序的效能,但是反而出现停顿。所以只能吧堆内存设置回1.5GB。网站慢,但是不至于停顿。
单体应用在较大的内存硬件上部署方式
单个虚拟机管理大内存的问题
使用若干个虚拟机逻辑集群管理硬件,可以解决上述的问题
package org.fenixsoft.classloading; /** * 被动使用类字段演示三: * 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的 类的初始化 **/ public class ConstClass { static { System.out.println("ConstClass init!"); } public static final String HELLOWORLD = "hello world"; } /** * 非主动使用类字段演示 **/ public class NotInitialization { public static void main(String[] args) { System.out.println(ConstClass.HELLOWORLD); } }
双亲委派的工作过程
双亲委派的好处
//1 public static void main(String[] args)() { byte[] placeholder = new byte[64 * 1024 * 1024]; System.gc(); } //2 public static void main(String[] args)() { { byte[] placeholder = new byte[64 * 1024 * 1024]; } System.gc(); } //3 public static void main(String[] args)() { { byte[] placeholder = new byte[64 * 1024 * 1024]; } int a = 0; System.gc(); }
public class StaticDispatch { static abstract class Human { } static class Man extends Human { } static class Woman extends Human { } public void sayHello(Human guy) { System.out.println("hello,guy!"); } public void sayHello(Man guy) { System.out.println("hello,gentleman!"); } public void sayHello(Woman guy) { System.out.println("hello,lady!"); } public static void main(String[] args) { Human man = new Man(); Human woman = new Woman(); StaticDispatch sr = new StaticDispatch(); sr.sayHello(man); sr.sayHello(woman); } } //结果 hello,guy! hello,guy!
public class DynamicDispatch { static abstract class Human { protected abstract void sayHello(); } static class Man extends Human { @Override protected void sayHello() { System.out.println("man say hello"); } } static class Woman extends Human { @Override protected void sayHello() { System.out.println("woman say hello"); } } public static void main(String[] args) { Human man = new Man(); Human woman = new Woman(); man.sayHello(); woman.sayHello(); man = new Woman(); man.sayHello(); } } //结果 man say hello woman say hello woman say hello
public static void main(java.lang.String[]); Code: Stack=2, Locals=3, Args_size=1 0: new #16; //class org/fenixsoft/polymorphic/DynamicDispatch$Man 3: dup 4: invokespecial #18; //Method org/fenixsoft/polymorphic/Dynamic Dispatch$Man."<init>":()V 7: astore_1 8: new #19; //class org/fenixsoft/polymorphic/DynamicDispatch$Woman 11: dup 12: invokespecial #21; //Method org/fenixsoft/polymorphic/DynamicDispatch$Woman."<init>":()V 15: astore_2 16: aload_1 17: invokevirtual #22; //Method org/fenixsoft/polymorphic/Dynamic Dispatch$Human.sayHello:()V 20: aload_2 21: invokevirtual #22; //Method org/fenixsoft/polymorphic/Dynamic Dispatch$Human.sayHello:()V 24: new #19; //class org/fenixsoft/polymorphic/DynamicDispatch$Woman 27: dup 28: invokespecial #21; //Method org/fenixsoft/polymorphic/DynamicDispatch$Woman."<init>":()V 31: astore_1 32: aload_1 33: invokevirtual #22; //Method org/fenixsoft/polymorphic/Dynamic Dispatch$Human.sayHello:()V 36: return
public class Dispatch { static class QQ {} static class _360 {} public static class Father { public void hardChoice(QQ arg) { System.out.println("father choose qq"); } public void hardChoice(_360 arg) { System.out.println("father choose 360"); } } public static class Son extends Father { public void hardChoice(QQ arg) { System.out.println("son choose qq"); } public void hardChoice(_360 arg) { System.out.println("son choose 360"); } } public static void main(String[] args) { Father father = new Father(); Father son = new Son(); father.hardChoice(new _360()); son.hardChoice(new QQ()); } } //结果 father choose 360 son choose qq
什么是动态类型语言?它与java语言和java虚拟机有什么关系?
public static void main(String[] args) {
int[][][] array = new int[1][0][-1];
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。