jvm学习笔记2

深入理解JVM的内存区域-0719

课前回顾

  • jdk-jre-jvm

  • jvm是一个假设在操作系统之上的微型操作系统,需要依赖java自带的类库

  • 跨语言、跨平台

  • java虚拟机主要是一种规范,主要有hotspot、j9、taobaovm、zing(土豪才能用)

  • 从内存结构开始发散学习

  • 线程私有区包括虚拟机栈、本地方法栈、程序计数器

  • 虚拟机栈默认大小1M

  • 运行java方法所需要的的数据指令存储在栈帧中

  • 操作数栈存在的意义?类似于操作系统的缓存作用

  • 直接内存,unsafe在1.9中计划删除

1. jvm内存处理全流程

1.1 jvm申请内存

  • 虚拟机参数设置(https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html)

    • -Xms30m(堆的初始大小) -Xmx30m(堆的最大大小) -XX:MaxMetaspaceSize=30m(元空间的最大大小)
  • 方法区和堆与内存无关,jvm启动就运行起来了

1.2初始化运行时数据区

1.3类加载

  • 方法区final变量、static变量、对象的类信息、

1.4执行方法

  • 执行java方法,栈帧入栈
  • new 对象,对象在堆里面创建,在栈帧里面会有一个该对象的引用(List l = new List<>();中的l)

1.5创建对象

2.从底层深入理解运行时数据区

2.1堆空间分代划分

eden、from、to属于新生代,tenured属于老年代

  • eden(所有的对象优先在eden区分配)
  • From
  • To
  • Tenured(老年代)

2.2 gc概念

  • -XX:+UseConMarkSweepGC -XX:-UseCompressedOops

    • 打开cms垃圾回收器,关闭压缩指针命令
  • System.gc()垃圾回收主动执行,不推荐做

    • 一个对象主动gc后会进入from区,回收不掉会进入to区,又返回from区,进过15次操作后,即操作年龄,就会进入老年代

2.3 JHSDB工具

  • 可视化,映射JVM的运行信息

    • sawindbg.dll

    • java -cp .\sa-jdi.jar sun.jvm.hotspot.HSDB

      • attach(添加) 通过jps把需要监控的进程号输入

        • Moniter ctrl-break
        • surrogate
        • main
        • listener
      • show the momery from the thread(栈所在区域)

        • 展示的是栈的使用情况

          • 上面的当前栈帧
            • kind:native会展示类型
          • 下面一个是前一个栈帧
            • Interptrted fram(蓝绿色,栈帧)
            • intertreted expression (黑色的,操作数栈)
            • interpteted locals area(局部变量表)
            • interptrted constans pool(橙色,常量池)
    • tools

      • object historims
        • char
        • String
      • 在tools里面搜索自己的包名称,可以找到对象在堆里面的信息
        • address
          • inspect进入对象‘
          • 操作系统上一个真实的物理地址
        • oop
        • class description
      • heap paramrter(对象所在区域)
        • gen 0:
          • eden、from、to、的起始地址(jvm划出来的虚拟地址)
        • gen 1:
          • old的起始地址

2.4 代码改造

  • system.gc15次
  • thread.sleep(Integer.max_value)

2.5 JHSDB使用

  • 查看栈 show the momery from the thread(栈所在区域)
  • 查看堆 heap paramrter(对象所在区域)
  • HSDB这个工具只有hotspot

3 虚拟机优化技术

3.1栈的优化技术

  • 调用方法的栈帧和被调用方法的栈帧 ,如果调用时有传入参数,这部分的栈空间是共享的,即调用方的操作数栈是被调用方的局部方法表。

4 深入辨析堆和栈

4.1 栈

  • 存储内容-线程运行时的内容,运行完毕即释放
  • 与线程的关系:线程独有,对单个线程可见,对其他线程不可见
  • 空间大小:默认1m,同时跑100个线程才消耗100m,实际循环时100个线程已经很多了

4.2 堆

  • 存储内容:对象(new出来的)

  • 线程可见,可以被所有的线程访问

  • 空间大小:相比栈要大

4.3 内存溢出(oom)

机器:2g 堆:1g 方法区:800m

机器剩余 200m

同时跑200线程 可运行

当跑201个线程时,机器死机

  • 让堆溢出
    • -Xms30m -Xmx30m -XX:+printGCDetails
      • new String[35 * 1000 * 100] 35m的数组
      • 直接就会 gc failure
      • oom -> java heap space
    • 不断地往list加对象
      • 不断触发垃圾回收
      • oom -> gc overhead limit exceeded(gc占据98%的资源,回收不足2%)
  • 方法区溢出
    • 方法区存储的是静态变量、常量、.class文件
    • 怎么不断往方法区里面塞.class文件
      • cglib包
        • while(true) Enhancer.create
        • -XX:+Metaspacesize = 10m -XX:+MaxMetaspacesize = 10m
        • oom : Metaspace
  • 本地直接内存溢出
    • ByteBuffer bb = ByteBuffer.allocateDirect(128 * 1000 * 1000)
    • -XX:MaxDirectMemeorySize = 100m
    • OOM : direct buffer memeory
    • 或者使用unsafe,但是不受控制
  • oom要重点关注是哪个区域抛出的

4.4 常量池(方法区)

常量池是虚拟机规范中定义的;

  • class常量池

    • javap -v xxx 可以生成一个class常量池
    • 存放的是编译时生成的字面量、符号引用
      • String a = “b”,"b"是a的字面量
      • 符号引用
        • Person类引用Tools类
          • 编译时不知道tools真实内存地址 Org.king.Tools — 符号引用
          • 类加载时就会把符号引用变成直接引用
  • 运行时常量池

    • 直接引用 -> 运行时常量池
      • jdk1.7以后可以放在堆上,逻辑上还是在方法区上,更适合做垃圾回收
  • 字符串常量池

    • String类分析(final)

      • final char value[]数组;Stirng对象的不可变
        • 可变就不安全,可能被恶意修改
        • hash值也不会轻易改变,可以确保hashmap key-value的稳定
        • 可以实现字符串常量池
      • int hash;
    • String的创建方式

      • String str = “abc”;

        • 编译时,会在常量池中创建常量,不会重复创建
        • 运行时,直接返回相关引用
      • String str = new String(”abc“)

        • 编译时,会在常量池中创建常量“abc”
        • new方法,会在堆空间创建String对象,并引用常量池中char数组,
      • Location location = new Location();

        location.setCity(“深圳”);

        • 直接在堆里面,不会在常量池中创建
      • String str = “ab” +“cd"+“ef”

        • 3个对象,效率最低 java -> class -> java
        • 编译器会自动优化成“abcded"
      • String str = “abvdef”;

        for(int i = 0;i<1000;i++)

        str = str + i;

        • 编译器会优化出StringBuilder
        • str = (new StringBuilder(String.valueof(Str)).append(i).toString());
      • String str = new String(“king”).intern();

        String str2 = new String(“king”).inter();

        • 在字符串常量池中去检查,有直接返回,没有则在字符串常量池中进行创建
        • a==b 输出true(这里需要认为是对象)
        • 推特公司优化内存,“深圳”、“北京“相同的字符串常量
      • 对象(堆中间的)引用(栈、方法区中的)、

      • ==是比较值,当是对象,比较的是地址,equal比较的是否同一个对象

    • 分配内存的方式

答疑

1.字符串常量池在哪个区 方法区

2.“abc"重复,统一放在字符串常量池

3.inter()方法 // new 对象,字符串常量池创建,在里面找,有就返回,没有就返回,第二次使用这个方法时,不会再创建对象,直接上面创建的对象

// 去字符串常量池找师傅有等于该字符串的对象(判断字面量),如果有,直接返回对象的引用

4.虚拟栈的优化

参数10是被调用方法的局部变量

传递的是引用,一样可以共享

5.字符串常量池不会被垃圾回收,垃圾回收的主要对象是堆里面的对象

6.值传递、引用传递、int缓存,需要一节课讲清楚

7.生产环境频繁gc怎么排查?需要体系化的jvm知识

8.String如果不加final,就不是常量了,就不需要字符串常量池了,如果不加,就是一个对象,就放在堆里面了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值