JVM学习

一.Java 内存区域(运行时数据区)
  1. 堆(Java堆):储存对象
  2. 栈:
  • 虚拟机栈:储存局部变量,栈信息(方法出口)
  • 本地方法栈:调用Native方法的栈信息,类似于虚拟机栈
  1. 方法区:储存类信息,静态变量,常量,及时编译器编译后的代码等。
  2. 其他:程序计数器,直接内存等。
二.Java 对象的创建过程
  1. 类加载检查
    如果没有加载类,则先加载类,(类加载过程:加载(读数据)、验证、准备(分配内存)、解析(符合引用换成直接引用)、初始化(init方法,执行各种类变量赋值及静态语句块))。
  2. 分配内存
    • 对象占用内存大小是确定的
    • 分配内存有“指针碰撞”和“空闲列表”两种,取决于垃圾收集器是否有整理功能。
    • 内存分配并发问题:要保证线程安全,一般通过Cas操作来分配内存,如果开启了TLAB会给每个线程预先分配一块内存。
  3. 初始化零值
  4. 设置对象头
    这个对象是哪那个类的实例、如何才能找到类的元数据信息、对象的哈希吗、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等。
  5. 执行init方法
三.对象访问定位的两种方式
  1. 句柄
    栈中存的是句柄地址,堆中有一个句柄池,句柄池中存了对象实际地址和对象类型的指针。好处是对象移动(GC?)的时候,不需要改变栈中的refrence值(句柄池应该不需要经常移动整理)。坏处是访问的时候多了一次指针定位开销。实际上就是中间加了一层进行了解耦。
  2. 直接指针
    栈中存的就是对象在堆中的地址。这种方式访问对象比较快,但是在对象移动的时候需要修改栈中的引用。
四.String类和常量池相关问题
  1. String str1 = "abc"; String str2 = new String("abc"); assert str1!=str2;
    因为str1是在常量池中的对象,str2是堆中的对象,所以不相等。
  2. String str1 = "abc"; String str2 = new String("abc"); String str3 = str2.intern();
    assert str1==str3; assert str2!=str3;
    因为str3和str1都是常量池中的对象。
  3. String str1 = "abc"; String str2 = "def"; String str3 = "abc"+"def"; String str4 = str1+str2; String str5 = "abcdef" assert str3==str5; assert str3!=str4;
    因为str3和str5都是常量池中相同对象。
五.Jvm中堆的划分

一共分为三个区:

  1. 新生代:主要是新对象和短生命周期对象。又划分为Eden区和两个幸存区,每次GC会把Eden区和一个幸存区中的存活对象挪到另外一个幸存区。
  2. 老年代:主要是大对象和存活时间长的对象。
  3. 永久代:存放类加载信息等(MaxPermSize)
六.什么时候对象会进入老年区?内存的分配与回收策略)
  1. 大对象会直接进入老年区(可配置)。
  2. 对象年龄超过设置的阈值。
  3. 如果Survivor空间中相同年龄所有对象大小总和大于Survior空间的一半,年龄大于或等于该年龄的对象就直接进入老年代。这个规则比较特别,可以理解成为了让对象进入老年代的过程更加平滑和均匀(如果没有这个规则,然后很多对象的年龄都一样的话,可能会出现某次minorGC过后大量的对象同时进入老年区)。
  4. minorGC的时候发现幸存区容量不够,则部分对象会进入老年区。
七.哪些情况下会minorGC,哪些情况下会majorGC?

1.minorGC:分配对象的时候新生代不够用了。
2.majorGC:
a. 老年代空间不足
b. 方法区空间不足
c. minorGC时,老年区连续内存大小如果小于新生代对象总和,且设置不允许担保分配失败,就会进行majorGC(因为minorGC的时候对象可能会进入老年区,需要确保老年区空间足够)(空间分配担保失败)。
d. 通过Minor GC后进入老年代的平均大小大于老年代的可用内存。

八.描述GC进行过程。

主要有两种:标记 - 清理 和 标记 - 整理。
标记的过程:通过OopMap(了解Safe Region)找到GCRoot(主要是栈和方法区内的对象,Class,Thread,各种局部变量),找到各个引用的对象进行标记。标记的时候需要stop the world(否则活着的对象可能被回收),CMS采用了“初始标记”——“并发标记”——“重新标记”的方式进行了优化。

九.ClassLoader 双亲委派模型

主要有3种ClassLoader:

  1. BootstrapClassLoader,加载Java种最基本的类,无法被程序引用到,加载JAVA_HOME/lib下的类
    2.ExtensionClassLoader,加载JAVA_HOME/lib/ext中的类
    3.ApplicationClassLoader,加载用户路径下的类
十.静态分派和动态分派
  • 静态分派
    所有依赖静态类型来定位方法执行版本的分派动作称为静态分派,其典型应用是方法重载(根据参数的静态类型来定位目标方法)。静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机执行的。
  • 动态分派
    在运行期根据实际类型确定方法执行版本。方法重写(@Override)。
十一.轻量级锁、偏向锁和重量级锁

你可能感兴趣的:(JVM学习)