JVM2.-创新互联

JVM体系结构

JVM

创新互联建站-专业网站定制、快速模板网站建设、高性价比儋州网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式儋州网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖儋州地区。费用合理售后完善,10余年实体公司更值得信赖。双亲委派机制
  • 类代码加载,并实例化的过程:
    • class.car → class loader
    • 加载 + 初始化:class loader → class car模版
    • new :相当于从class car模版实例化一个对象
    • getClass:和new相反。getClassLoader可以获得加载器
  • 双亲委派机制:new 一个对象,寻找类的过程:
    • 现在boot加载器中寻找(jre/lib/rt.jar)
    • 再去ext加载器中寻找(jre/lib/ext/…)
    • 最后在app加载器(用户写的)寻找
  • 双亲委派的作用:
    • 防止用户自己写系统自带的类。例如自己写String是无效的,除非修改rt.jar,但是修改会导致所有的使用String的其他类崩溃
public class Car {public static void main(String[] args) {Car car1 = new Car();
        Car car2 = new Car();
        System.out.println(car1 == car2);       //false,故其hascode不同
        System.out.println(car1.getClass() == car2.getClass()); //true,故其hascode相同
        System.out.println(car1.getClass().getClassLoader());     //AppClassLoader
        System.out.println(car1.getClass().getClassLoader().getParent());   //ExtClassLoader       

    }
}
SandBox机制
  • 组成
    • 字节校验码:要求用户写的代码符合要求。但是核心类(java/…和javax/…)不需要检验
    • 类装载器(其实是双亲委派机制在起作用):不可改变核心类
Native
  • 代码:
public class Demo1 {
    public static void main(String[] args) {
        new Thread(()->{

        },"adair");
    }
    //native:java本身无法完成,无方法体,需要调用底层
    //native会进入本地方法栈 → JNI → 本地方法库
    //JNI作用,扩展java语言,融合不同编程语言为java使用。
    //例如java驱动打印机,管理系统,写外挂
    private native void start0();
}
内存 方法区
  • 方法区是一种规范,实现之前是永久区,如今是元空间。所有定义方法的信息都保存在该区域。
  • 静态变量、常量、类信息(构造方法/定义接口)、运行时的常量池都在方法区(static、final、class、 常量池)。但是对象存在于堆中
  • main最先执行,最后结束
  • 线程结束,栈内存就释放。对于栈不存在垃圾
  • 栈内:基本类型 + 对象引用 + 实例方法
  • 栈内以栈帧为单位
  • 程序正在运行的方法,一定在栈的顶部
  • JVM有三种hotspotJ9VMJRockit

  • 一个JVM只有一个堆,且堆内存的大小可变

  • 堆的东西:类、方法、常量、变量、 真实对象

  • 堆的三个区域:

    • 新生区:伊甸园eden、幸存去s0(from)、s1(to)。轻GC
    • 养老区:常用的数据。重GC(Full GC)
    • 永久区(元空间)
  • 新生区:类的诞生 + 甚至死亡的地方。

  • eden:对象被new的地方,满了就会触发轻GC,幸存者存放在s1

  • 如果幸存区满了,引发重GC(全局清理),送入养老区

  • 如果养老区满了,则OOM

  • 永久区:常驻内存,存放JDK自身的Class对象。interface元数据,存储的是java运行时的环境。这个区域无GC,关闭JVM即可释放此区域。一个启动类,加载大量第三方jar包,或者生成大量的反射类,直到OOM

    • jdk1.6 :永久代,常量池在方法区
    • jdk1.7:永久代(退化),常量池在堆中
    • jdk1.8:无永久带,常量池在元空间(不再JVM中,本地内存)中
  • 元空间、永久区、方法区、常量池关系:java8 hotspot取消了永久区。方法区是一个规范,规范没变,它就一直在,取而代之的是元空间,元空间存储类的元信息,静态变量和常量池等并入堆中。

  • 元空间:逻辑存在,物理不存在

  • JVM调参:

public class Car {public static void main(String[] args) {//jvm试图使用的大内存
        long l = Runtime.getRuntime().maxMemory();
        //jvm初始化的内存
        long l1 = Runtime.getRuntime().totalMemory();
        //默认大为电脑内存的1/4,初始化为1/64
        System.out.println(l/(double)1024/1024);
        System.out.println(l1/(double)1024/1024);

        //jvm调参:-Xms1024m -Xmx2g -XX:+PrintGCDetails
    }
}
Jprofiler

在一个很大项目中,出现了OOM,OOM要想捕获用Error e捕获,如何使用专业工具排错

  • Jprofiler作用
    • 分析dump文件,定位泄露
    • 获得堆的数据
  • 安装过程:
    • 现在idea中找好Jprofiler接口
    • 然后下载Jprofiler,记住安装路径(environment)
    • 然后配置接口到jprofiler9/bin/jprofiler.exe
  • Vm options配置-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
  • 点击运行代码(死循环),即可生成带有OOM的dump文件,使用jprofiler打开即可分析
  • dump文件分析:
    • 可以查看大的数据在哪里,很大程度OOM
    • Thread Dump可查看线程的main函数中具体第几行出现错误
GC

JVM的GC几乎全部在堆中,对堆的清理大部分在eden区

  • 轻GC:在新生区进行操作,操作后会将eden活的对象移到幸存区,从而eden为空。当一个对象经过默认值15次还没死,就去养老区
  • Full GC:全局
  • GC算法:
    • 引用计数法:顾名思义。计数器本身也会有消耗,辣鸡
    • 复制算法:s0 s1相互转换,没有内存碎片,但是永远有一半未使用
    • 标记清除算法:先进行标记,再清除。两次扫描浪费时间,有内存碎片。
    • 标记清除压缩
总结

内存效率:复制算法 >标记清除 >标记压缩 (时间复杂度)

内存整齐度:复制算法 = 标记压缩 >标记清除

内存利用率:标记压缩 = 标记清除 >复制算法

  • JVM调优:没有最好的算法,只有最合适的算法 -->分代收集算法
    • 年轻代:存活低、故使用复制算法
    • 老年代:区域大,存活高。使用标记清楚 + 标记压缩 实现
JMM
  • JMM就是java memory module,相当于是一个规则
  • 作用:
    • 缓存一致性协议,用于定义数据读写的规则
    • JMM定义了线程和内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory),每个线程都有一个私有的本地内存(local memory),线程的本地内存是从主内存复制的,由于多个线程对一个对象进行操作,因此需要解决volatile

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


分享文章:JVM2.-创新互联
文章URL:http://ybzwz.com/article/coiddo.html