Jvm的组成、垃圾回收机制-Java基础

  1. Jvm的组成、垃圾回收机制

1.1 Jvm组成

JVM有6个部分:JVM解释器、指令系统、寄存器、栈、存储区和碎片回收。

1)JVM解释器

虚拟机处理字段码的CPU。

2)指令系统

指令由操作码和操作数组成。

3)寄存器

JVM有自己的虚拟寄存器,可以快速的与JVM的解释器进行数据交换。

4)栈

指令执行时数据和信息存储的场所和控制中心,提供给JVM解释器运算所吸引的信息。

5)存储区

存储区分为两类:常量缓冲池(存取名称、方法和字段名、串常理)和方法区(Java方法的字节码)。

6)碎片回收

用过的java类的具体实例从内存进行回收,开发人员免去控制内存的麻烦。分代收集技术,利用对象在程序中生存的时间划分成代,以此为标准进行碎片回收。

1.2 垃圾回收机制

GC看对象是否活动确定是否收集对象。

1)触发GC的条件

GC在线程运行优先级最低,没有线程在运行时被调用。堆内存不足时GC会被调用,内存不足强制调用GC线程。如果还是不足会两次调用GC,如果还不足,将会报错”out of memory”,java应用将停止.

  1. Scavenge GC 新对象生成,在Eden申请空间失败,Eden区GC频繁。
  2. Full GC 对整个堆进行整理,包括Young、Tenured和Perm。较慢,使用次数应尽量减少。触发条件:1)年老代被写满;2)持久代被写满;3)System.gc()被显示调用;4)上一次GC之后Heap的各域分配策略动态变化。

2)方法

A. System.gc()方法 不管有哪种垃圾回收算法,都可以请求java垃圾回收。java -verbosegc classfile查看堆内存。

B. Finalize()方法 缺省机制来终止该对象心释放资源。protected void finalize() throws Throwable在finalize()方法返回之后,对象消失,垃圾收集开始执行。

使用Finalize()是存在着垃圾回收器不能处理的特殊情况,防止内存泄漏。

1.3 减少GC开销的措施

(1)不显示调用System.gc()。会增加间歇性停顿的次数,大大影响系统内存。

(2)减少临时对象的使用。临时对象在跳出函数调用会成为垃圾,减少使用,减少主GC的机会。

(3)对象不用时最好显示置为null。一般为null就要被处理,提高处理效率。

(4)尽量使用StringBuffer,而不用String来累加,每次改变就会创造新的对象。

(5)能使用基本类型Int,Long,就不用Integer、Long对象。最好使用基本变量。

(6)尽量减少使用静态对象变量。静态变量属于全局变量,不会被GC回收,会一直占用内存。

(7)分散对象创建或删除的时间。集中处理会导致大量需要内存,面对这种情况主GC频率会增加,会导致系统性能。

1.4 对象在JVM堆区的状态

(1)可触及状态。程序中还有变量引用,此对象为可触及状态。

(2)可复活状态。finalize方法内的代码有可能将对象转为可触及状态,否则对象转化为不可触及状态。

(3)不可触及状态,就被GC回收。

1.5 常用垃圾收集器

(1)标记-清楚收集器mark-Sweep

(2)复制收集器        Copying

(3)标记-压缩收集器 Mark-Compact

(4)分代收集器   Generational

1.6 垃圾回收算法

(1)tracing算法-标记清除

标记清除回收器。标记阶段用于标记需要回收的对象,清除阶段是把标记对象清楚。采用从根集合(GC Roots)进行扫描。

(2)Copying算法-复制

把内存容量分为大小相等的块,当一块内存用完了,还有存活着的对象复制到另一块当中,不容易出现内存碎片。从根集合(GC Roots)中扫描活动对象,并将每个 活动对象复制到空闲面。

(3)Compacting算法-标记整理

首先进行标记,标记完之后不是直接清理回收对象,而是移动到一端,然后清理到边界外的内存。成本高,但是解决了内存碎片的问题。

(4)Generation算法-分代收集

分代收集算法,常用算法。核心思想根据对象存活的生命周期将内存划分为若干不同的区域。分为老年代和新生代,老年代特点每次垃圾收集只有少量对象需要被回收,新生代特点是每次回收都有大量对象需要被回收,可以根据不同代的特点采取最适合的收集算法。

新生代:新创建的对象存放的位置。当对象从这块内存区域消失时,发生了一次“minor GC”。

老年代:被复制过来的年轻对象,GC发生的次数比年轻代少。major GC”(或“full GC”)发生。少量对象需要被回收。

1.7 JVM把内存划分成了如下几个区域

1.方法区(Method Area)称为持久代,加载类信息、静态变量、构造函数、final定义的常量等,全局共享,执行GC情况少。超出大小会抛出OutOfMemory:permGen Space异常。运行时常量池(Runtime Constant Pool)是方法区的一部分,用于存储编译器生成的常量和引用。

2.堆区(Heap)GC最频繁,所有线程共享,在虚拟机启动时候创建。注意存放对象实例及数组,new出来的对象都存储在该区域。

3.虚拟机栈(VM Stack)占用操作系统内存,一个线程对应一个虚拟机栈,线程私有,每个方法被执行时产生一个栈帧stack frame,存储局部变量,调用方法,栈帧入站,调用结束,出栈。局部变量表,存取方法相关局部变量,编译期间确定,运行时不再改变。

虚拟机栈异常有StackOverFlowError(栈溢出,线程调用栈深度大于虚拟机允许的深度)和OutOfMemoryError(内存溢出,一般不允许动态扩充,线程可以一直申请栈,直到内存不足,抛出该异常)。

4.本地方法栈(Native Method Stack)native方法的执行,存储了每个native方法的执行状态。

5.程序计数器(Program Counter Register)很小的内存区,在cpu上面,程序员无法操作它。作用时:JVM解释字节码.class文件时,存储当前线程执行的字节码的行号。改变程序计数器来取下一条指令、分支、循环等。其属于线程私有,与计数器一一对应。Java方法记录虚拟机字节码指令地址,native则计数器值为空。此内存不会抛出OutOfMemory.

Android要不要手动调用System.gc()呢?

陆奇:如果不懂产品,不可能成为一个好的工程师,不仅要动产品,还需要动商业,动生态,因为你的工作的责任是把需求,把平台、把开发流程、把你的团队为将来做准备。

上一节说了JVM的垃圾回收机制,那么Android要不要手动调用System.gc()呢?

在Android5.0之前,可以直接调用gc

public static void gc() {

    Runtime.getRuntime().gc();

}

在Android5.0之后,需要:

    1)System.gc()和System.runFinalization()同时调用

    2)直接调用Runtime.getRuntime().gc()


    /**
     * @android 5 之后调用 gc
     */
    private static boolean justRunFinalization;
    //private static int lock = 0;
    public static void gc(){
        boolean ifRunGC;
        synchronized(lock){
            ifRunGC = justRunFinalization;
            if(ifRunGC){
                justRunFinalization = false;
            }else{
                runGC = true;
            }
        }
        if(ifRunGC){
            Runtime.getRuntime().gc();  //只有当shouldRunGC为true时,才会真的去gc.shouldRunGC即justRanFinalization
        }
    }
    public static void runFinalization(){  //执行对象的finalize()方法
        boolean ifRunGC;
        synchronized(lock){            //只有runGC为true才会触发gc
            ifRunGC = runGC;
            runGC = false;
        }
        if(ifRunGC){
            Runtime.getRuntime().gc();
        }
        Runtime.getRuntime().runFinalization();
        synchronized(lock){
            justRunDinalization = true;   //justRunDinalization才会赋值为true
        }
    }

 

扫码关注一起随时随地学习!!!就在洋葱攻城狮,更多精彩,等你来!!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洋葱ycy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值