JVM类加载器详细
JVM图
用new创建的对象在堆
函数中的临时变量在栈区
java中的字符串在字符串常量区
一、类初始化
Java程序初始化顺序:
- 父类的静态代码块
- 子类的静态代码块
- 父类的普通代码块
- 父类的构造方法
- 子类的普通代码块
- 子类的构造方法
二、类加载机制
三、JVM的内存
JAVA的JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method)
栈区:
- 1.每个线程包含一个栈区,栈中只保存方法中(不包括对象的成员变量)的基础数据类型和自定义对象的引用(不是对象),对象都存放在堆区中
- 2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
- 3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
堆区:
- 1.存储的全部是对象实例,每个对象都包含一个与之对应的class的信息(class信息存放在方法区)。
- 2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身,几乎所有的对象实例和数组都在堆中分配。
方法区:
- 又叫静态区,跟堆一样,被所有的线程共享。它用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
四、GC
CMS的GC过程有6个阶段(4个并发,2个暂停其它应用程序)
- 初次标记(STW initial mark)
- 并发标记(Concurrent marking)
- 并发可中断预清理(Concurrent precleaning)
- 最终重新标记(STW remark)
- 并发清理(Concurrent sweeping)
- 并发重置(Concurrent reset)
五、jvm堆
六、GC触发条件
在程序空闲时。
-
程序不可预知的时候/手动调用 System.gc() 。不要手动调用GC,不管是 JVM 自己调用还是手动调用都会使系统陷入短暂的停顿,给垃圾回收让路,手动调用就违背了我们优化 GC 的初衷了
-
堆内存不足时 GC 会被调用。当应用线程在运行,并在运行过程中穿件对象,若这时内存空间不足,JVM就会强制的调用 GC ,一遍回收内存用于新的分配。若GC 一次之后仍不满足内存分配的要求,JVM会再次进行两次 GC 做进一步尝试,若还是不满足需求则会抛出 “out of memort” 的错误使应用异常停止
七、是否符合垃圾收集器收集标准
在java语言中,判断一块内存空间是否符合垃圾收集器收集标准的标准只有两个:
1.给对象赋值为null,以下没有调用过。
2.给对象赋了新的值,重新分配了内存空间。
八、一条进程的栈区、堆区、数据区和代码区在内存中的映射
1>栈区:主要用来存放局部变量, 传递参数, 存放函数的返回地址。.esp 始终指向栈顶, 栈中的数据越多, esp的值越小。
2>堆区:用于存放动态分配的对象, 当你使用 malloc和new 等进行分配时,所得到的空间就在堆中。动态分配得到的内存区域附带有分配信息, 所以你 能够 free和delete它们。
3>数据区:全局,静态和常量是分配在数据区中的,数据区包括bss(未初始化数据区)和初始化数据区。
注意:
1)堆向高内存地址生长;
2)栈向低内存地址生长;
3)堆和栈相向而生,堆和栈之间有个临界点,称为stkbrk。
1、一条进程在内存中的映射
假设现在有一个程序,它的函数调用顺序如下:
main(…) ->; func_1(…) ->; func_2(…) ->; func_3(…),即:主函数main调用函数func_1; 函数func_1调用函数func_2; 函数func_2调用函数func_3。
当一个程序***作系统调入内存运行, 其对应的进程在内存中的映射如下图所示: