深入理解JVM

深入理解JVM


1. JVM运行机制及原理

JVM是JRE的一部分,是一个虚构出来的计算机,有着一套完整的硬件架构体系。
java程序之所以拥有着跨平台性,这也就是jvm的功劳。首先java源程序.java文件通过编译器编译成.class文件,然后java解释器又将这编译后的字节码,解释成特定的机器码运行。
JVM运行机制及原理

2. jvm内存机制

运行时数据区
Jvm内存区域分为三大块:类装载器、运行时数据区、执行引擎。

2.1 类装载器

类装载器负责加载程序中的类型(类和接口),并赋予唯一的名字。同时类装载器分为启动类装载器和用户自定义类装载器。

2.2 运行时数据区

运行时数据区2
- 运行时数据区由以下几个部分组成:

  1. 堆内存:
    存放程序运行时new出来的对象,同时堆内存在JVM中属于线程共享的,因此对象内存的分配均需要进行加锁,这也导致了new对象的开销是比较大的。开发中也常使用单例模式或者配置一个bean容器,来创建一个常用的实例对象。
  2. 栈内存:
    每个方法被执行的时候,都会同时创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、对象引用地址、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
  3. 程序计数器:
    一块很小的内存空间,作用是当前线程所执行的字节码的行号指示器。
  4. 本地方法栈:
    与虚拟机栈作用很相似,区别是虚拟机栈为虚拟机执行java方法服务,而本地方法栈则是为虚拟机用到的Native方法服务。(Java程序调用了非Java代码)
  5. 方法区:
    用于存放已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。
    方法区同时包含运行时常量池,用于存放编译期生成的各种字面量和符号引用。这里也有一个特性,就是对象比较。(注意:jdk1.8常量池位于方法区中,但常量池引用的字符串实例却在堆中。)
    运行时常量池

2.3 执行引擎

用来执行字节码或本地方法。主要采用方式:解释,即时编译,自适应优化。

3. JVM垃圾回收

  1. GC什么时候启动
    GC是一个动态优先级的守护进程。当内存资源低到一定限度时便会自动运行,从而实现对内存的回收。这就是垃圾回收的时间不确定的原因。
    告诉程序尽快启动一次GC代码:system.gc()
  2. 被GC回收的对象
    程序运行期间,所有对象实例存储在运行时数据区域的heap中,当一个对象不再被引用(使用),它就需要被收回。在GC过程中,这些不再被使用的对象从heap中收回,这样就会有空间被循环利用。
  3. GC是如何回收对象的
    在对对象的生命周期特征(eden or survivor)进行分析之后,采用了分代的方式进行对象的收集,以缩短GC对应用造成的暂停。
    这种"自适应式"垃圾回收机制,会自动的进行分代、停止-复制、标记-清扫等方式进行垃圾回收。它会根据不同的环境选择不同的处理方式。
  4. JVM次世代划分
    新生代与旧生代策略作用于堆内存中,而持久代策略作用于方法区中
    • 新生代 Young Generation
      1. Eden Space 任何新进入运行时数据区域的实例都会存放在此
      2. S0 Suvivor Space 存在时间较长,经过垃圾回收没有被清除的实例,就从Eden 搬到了S0
      3. S1 Survivor Space 同理,存在时间更长的实例,就从S0 搬到了S1
    • 旧生代 Old Generation/tenured
      同理,存在时间更长的实例,对象多次回收没被清除,就从S1 搬到了tenured
    • 持久代 Perm
      存放运行时数据区的方法区
  5. 开发中可回收垃圾产生演示
    JVM 分别对新生代和旧生代采用不同的垃圾回收机制

何为垃圾?

Java中那些不可达的对象就会变成垃圾。那么什么叫做不可达?其实就是没有办法再引用到该对象了。主要有以下情况使对象变为垃圾:

  • 对非线程的对象来说,所有的活动线程都不能访问该对象,那么该对象就会变为垃圾。

  • 对线程对象来说,满足上面的条件,且线程未启动或者已停止。

    例如:
    (1)改变对象的引用,如置为null或者指向其他对象。
    Object x=new Object();//object1
    Object y=new Object();//object2
    x=y;//object1 变为垃圾
    x=y=null;//object2 变为垃圾
    (2)超出作用域
    if(i==0){
    Object x=new Object();//object1
    }//括号结束后object1将无法被引用,变为垃圾
    (3)类嵌套导致未完全释放
    class A{
    A a;
    }
    A x= new A();//分配一个空间
    x.a= new A();//又分配了一个空间
    x=null;//将会产生两个垃圾
    (4)线程中的垃圾
    class A implements Runnable{
    void run(){
    //…
    }
    }
    //main
    A x=new A();//object1
    x.start();
    x=null;//等线程执行完后object1才被认定为垃圾
    这样看,确实在代码执行过程中会产生很多垃圾,不过不用担心,java可以有效地处理他们。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值