01-01-JAVA基础-01-JVM-01-内存与垃圾回收-01-JVM与Java体系结构-03运行时数据区概述及线程


03运行时数据区


目录:

1、 运行时数据区内部结构与 JVM中的线程说明
2、 PC寄存器概述
3、 虚拟机栈
4、栈的相关面试题
5、堆
6、方法区
 

1、 运行时数据区内部结构与JVM中的线程说明

 
 
 
 

 

 

2、  PC寄存器概述


3、 虚拟机栈

 
 
 
 

1、局部变量表

 
 
 
 
 

2、操作数栈

 
 
 
 

3、动态链接

 
 
 
 
 

4、方法返回地址

 

5、栈针的附加信息

 
 
 

4、栈的相关面试题

 
 

5、堆

 
1. 堆的概述
 
①.存放的东西:对象本身、全局变量 [ 成员变量 ]
 
②. 特点:
        a.它是线程共享的,堆中对象都需要考虑线程安全的问题
        b.有垃圾回收机制
 
2.  堆内存内部结构
 
①. 所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx 和Xms来控制
 
②. 堆被划分为新生代和老年代,新生代又被进一步划分为Eden(伊甸园)和Survivor(幸存者)区,老年代,在后面不是堆区是永恒代(方法区)
 
③. 伊甸园满了,就会触发gc(minor gc),而gc就会把标识为垃圾的对象干掉,不是垃圾的对象就要转移到幸存区,把伊甸园让出来给新的对象用
 
 
 
3.  养老区
        养老区用于保存从新生区筛选出来的Java对象,一般池对象都在这个区域活跃
 
①. Eden 和survivor的比例是8:1,年轻代中的对象基本都是朝生夕死(80%以上),老年代比年轻代内存大。如果老年代内存满了,就会触发majorGC 或者 full GC
 
②. full GC 就会出现所谓的STW(stop the world)现象,即所有的进程都挂起等待清理垃圾
 
③. major GC 是回收老年代的垃圾;Full GC是回收老年代和年轻代的垃圾
 
    如果出现 java.lang.OutOfMemoryError : Java heap space 异常,说明Java虚拟机的堆内
存不够:由如下两种原因
    1.Java 虚拟机的堆内存设置不够,可以通过参数 -Xms 、Xmx 来调优
    2.代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)
 
5.  永久代
永久储存是一个常驻内存区域,用于存放JDK自身所携带的Class,Interface 的元数据,也就是说它存储的是运行坏境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM才会释放此区域所占用的内存
 
 
//java.lang.OutOfMemoryError : PermGen space如果出现
java.lang.OutOfMemoryError : PermGen space, 说明是Java虚拟机堆永久代Perm内存设置不够。
一般出现这样情况,都是程序启动需要加载大量的第三方jar包。例如:在 一个Tomcat 下部署了太多的应用。需要大量动态反射生成的类不断被加载,最终导致Perm区被占满。
 
 
①. Jdk 1.6 及之前:有永久代,常量池1.6在方法区
②. Jdk 1.7 :有永久代,但已经逐步 " 去永久代 ",常量池1.7 在堆中
③. jdk 1.8 及之后: 无永久代,常量池1.8在元空间
 
 
JdK1.7之前
 
 
Jdk1.7开始
 
 
 
 
一.常量池共有三类:
 
1.运行时常量池
 
2.Class文件常量池
 
3.字符串常量池
 
二. 详解
 
常量池(Constant Pool)
1.1 常量池(Class文件常量池):.java经过编译后生成的.class文件,是Class文件的资源仓库。
 
1.2 常量池中主要存放俩大常量:字面量(文本字符串,final常量)和符号引用(类和接口的全局定名,字段的名称和描述,方法的名称和描述),如下图:
 
 
2. 运行时常量池(Constant Pool)
 
运行时常量池是方法区的一部分。在Class常量池中,用于存放编译期间生成的字面量和符号量,在类加载完之后,存入运行时常量池中。而运行时常量池期间也有可能加入新的常量(如:String.intern方法)
 
3. String常量池,
 
String常量池,JVM为了减少字符串对象的重复创建,在堆区开一段内存存放字符串。
 
 
 
6.  jdk1.7 和 jdk1.8 堆中结构区别
①.jdk1.7 堆中的结构
 
 
 
②. jdk 1.8 堆中的结构
 
 
 
        //Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        //java虚拟机中堆内存是2022m也就是2g多
        System.out.println(Runtime.getRuntime().maxMemory()/1024/1024);
        //这里没有超过God 111 可以输出
        /*byte[]byteArray=new byte[1*1024*1024*2000];
        System.out.println("God 111");*/
        //这里超过了2g多,会抛出Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        byte[]byteArray=new byte[1*1024*1024*2020];
        System.out.println("God 111");
 
 
7.  jps | jmap | jconsole的使用
    public class test {
        public static void main(String[] args) {
            System.out.println("1...."); try { TimeUnit.SECONDS.sleep(30);  } catch (InterruptedException e) {e.printStackTrace();}
            byte[]bytes=new byte[1024*1024*10];
            System.out.println("2....");
            try { TimeUnit.SECONDS.sleep(30);  } catch (InterruptedException e) {e.printStackTrace();}
            bytes=null;
            System.gc();
            System.out.println("3....");
            try { TimeUnit.SECONDS.sleep(20);  } catch (InterruptedException e) {e.printStackTrace();}
        }
    }
 
 
 
演示jps和jmap如下:
1.在byte还没创建前
 
 
2.创建了一个10M的byte的数组
 
 
 
 
 
jconsole演示:
 
 
 

 
6、方法区
 
1. 方法区的概述
     存储的东西:
    静态变量+常量+类信息+运行时常量池存在方法区中 [ 掌握 ]
①. 所有Java虚拟机线程共享的区域,存储了类结构相关的信息 [ 成员变量、方法、构造器 ]等
 
②. 方法区的创建是在Java 虚拟机启动时被创建
 
③. 方法区时逻辑上时堆的一个组成部分,但是在不同虚拟机里头实现是不一样的,最典型的就是永久代(PermGen space)和元空间(Metaspace)
注意:方法区时一种规范,而永久代和元空间是它的一种实现方式
 
④. 方法区存在OOM现象
 
 
2. 常量池和运行时常量池
 
①. 常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
 
②. 运行时常量池,常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址
 
③. 进入class的目录,javap -v 类.class
二进制字节码(类基本信息+常量池+类的方法定义[包含了虚拟机指令])
如下代码重点掌握
 
public class StringTableDemo1 {
    /*
     1.常量池中的信息,都会被加载到运行时常量池,这是a b ab 都是常量池中
     的符号,还没有变成Java字符串对象
     2.ldc #2 会把a符号变成字符串对象,会为StringTable开辟一个空间,
     在StringTable中查看a是否存在,如果不存在,就添加进去,如果存在,
     就用StringTable中有的;b ab都是这个过程
    * */
    public static void main(String[] args) {
        String s1="a";
        String s2="b";
        String s3="ab";
        //new StringBuilder().append("a").append("b").toString();
        //new String("ab");
        String s4=s1+s2;
        //s3是串池中的 s4是在堆里面的 两个对象[new StringBuilder()| new String()]
        System.out.println(s3==s4);//false
        //直接去串池中找有没有ab,有的话用串池中有的,没有的话创建ab,放入串池
        //javac 在编译期间的优化,结果已经在编译期间确定为ab
        String s5="a"+"b";
        System.out.println(s3==s5);//true
    }
}
 
 
 

 
作者: Darren
电话:15110448224
QQ:603026148
以上内容归 Darren 所有,如果有什么错误或者不足的地方请联系我 ,希望我们共同进步。
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值