JVM梳理

堆内存:
在JVM开启的时候就会被创建
存放对象实例,几乎所有的对象实例都在这里分配内存
存放由new创建的对象和数组,即动态申请的内存都存放在堆内存


栈内存:

栈内存是用来存放在函数中定义的一些基本类型的变量和对象的引用变量
例子:局部变量存放在栈;函数调用参数,函数返回值,函数返回地址存放在栈

方法区:
它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域。
jdk1.8之后永久代已经被移除

虚拟机栈(java栈):
描述的是java方法执行的内存模型
每个方法被执行的时候都会创建一个"栈帧",用于存储局部变量表(包括参数)、操作栈、方法出口等信息。每个方法被调用到执行完的过程,
就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。


本地方法栈:
本地方法栈与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。


程序计数器:
程序计数器是用于标识当前线程执行的字节码文件的行号指示器。多线程情况下,每个线程都具有各自独立的程序计数器,所以该区域是非线程共享的内存区域。
当执行java方法时候,计数器中保存的是字节码文件的行号;当执行Native方法时,计数器的值为空。

JVM调优
JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat等小巧的工具
jps:主要用来输出JVM中运行的进程状态信息。
jstack:主要用来查看某个Java进程内的线程堆栈信息。
jmap:用来查看堆内存使用状况,一般结合jhat使用。
jstat(JVM统计监测工具):检测一些GC,内存的统计信息

vm垃圾回收:
新生代(Eden,Survior1,Survior2),老年代,永久代(jdk1.8已经被移除,用元空间代之)
永久代用的是虚拟机内存,元空间用的是物理内存
内存分配策略:对象优先分配进新生代,大对象进入老年代,长期存活的对象进入老年代


Minor Gc:发生新生代的的垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快
Full GC:发生在老年代的GC,速度一般会比Minor GC的慢10倍以上

判断对象是否死亡:
1.引用计数器法:给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0的对象就是不可能再被使用的
2、可达性分析算法: 以“GC Roots” 对象作为起点,从这些节点开始向下搜索,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

垃圾回收算法进行回收:
3、标记-清除算法:即直接将标记为死亡的对象清除,缺点是会产生垃圾碎片
4、标记-整理算法:即将可用的对象统一向一端移动,将边界外的对象清除
5、复制算法:将内存分为大小相同的两块
4、分代回收算法:将堆内存分为老年代和新生代,分代整理

类加载过程:
加载,连接(验证,准备,解析),初始化
 

类加载器:
根(Bootstrap)类加载器:
负责加载JAVA_HOME\lib目录中并且能被虚拟机识别的类库到JVM内存中,该类加载器无法被Java程序直接引用:

标准扩展(Extension)类加载器:
该加载器主要是负责加载JAVA_HOME\lib\,该加载器可以被开发者直接使用。

应用程序类加载器(Application ClassLoader)(系统(System)类加载器):
负责加载用户类路径(Classpath)上所指定的类库,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器

类加载机制:
全盘负责
双亲委派: 先执行父类加载器,直到父类说自己加载不了,在执行子类加载器
缓存机制

描述一下JVM加载class文件的原理机制?
1.装载:查找和导入class文件;
2.连接:
      (1)检查:检查载入的class文件数据的正确性;
      (2)准备:为类的静态变量分配存储空间;
      (3)解析:将符号引用转换成直接引用(这一步是可选的)
3.初始化:初始化静态变量,静态代码块。
      这样的过程在程序调用类的静态成员的时候开始执行,所以静态方法main()才会成为一般程序的入口方法。类的构造器也会引发该动作。

相关推荐