JVM学习笔记

JVM

JVM的定义:java的运行环境。
JVM的优点:
1.自动内存管理,垃圾回收环境
2.数组下标月结检查
3.多态
4.一次编写,到处运行
比较jdk,jre,jvm

在这里插入图片描述
JVM的结构
在这里插入图片描述

JVM内存结构

程序计数器

java代码的执行流程:java源代码先编译成为二进制字节码,二进制字节码放入到解释器中,转换成机器码,机器码最后交由CPU执行。
作用:程序计数器用来记住二进制字节码中的下一条执行jvm指令的执行地址。在解释器执行完上一条指令时,会调用程序计数器中的地址,执行下一条jvm指令。
特点:线程私有的。
不会出现内存溢出。

虚拟机栈

虚拟机栈的定义:线程运行需要的内存时间。每个栈中可以装有若干个栈帧。
栈帧的定义:每个方法运行时需要的内存。
活动栈帧:对应着当前正在执行的方法。

虚拟机栈常见的问题:

垃圾回收是否会涉及栈内存?

不会,栈内存在方法调用完成后就会进行处理,垃圾回收涉及到的是堆内存。

栈内存分配越大越好吗?
不是,栈内存越大,线程数量会减少,物理内存是固定的,栈内存越大,最大的线程数量就会越少。
方法内的局部变量是否线程安全?
如果方法内的局部变量是私有的,那么局部变量不会有线程安全的问题。
如果方法内的局部变量是共享的,那么局部变量会产生线程安全问题。
如果局部变量引入了对象并逃离方法的作用方法,需要考虑线程安全。

栈内存溢出问题:

栈帧过多导致栈内存溢出。
示例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

栈帧过大导致栈内存溢出。

定义:Heap堆:通过new关键字都会使用堆内存
特点:是线程共享的,需要考虑线程安全问题,具有垃圾回收机制。
堆内存溢出:

示例:

import java.util.ArrayList;
import java.util.List;

public class lianxi1 {
    public static void main(String [] args){
        int i=0;
        try {
        List<String> list=new ArrayList<>();
        String a="hello";
        while (true){
            list.add(a);
            a=a+a;
            i++;
        }
        }catch (Throwable e){
            e.printStackTrace();
            System.out.println(i);
        }
    }
}

在这里插入图片描述

内存诊断方法

jps工具:查看当前系统中哪些java进程
jmap工具:查看堆内存占用情况
jconsole工具:图形界面的,多功能的监测工具,可以连续监测。
演示:
运行程序

在这里插入图片描述
然后输入jps,查看当前系统中的java进程
在这里插入图片描述
然后输入jmap -heap 10712查看堆内存的占用情况。
堆内存的占用情况
在这里插入图片描述
除了上述之外还有jvisualvm,
在这里插入图片描述

方法区

方法区结构
在这里插入图片描述
方法区在1.8之前内存溢出会导致永久代内存溢出,java. lang . OutOfMemoryError: PermGen space
方法区在1.8之后内存溢出会导致元空间内存溢出, java. lang . OutOfMemoryError: Metaspace

常量池

示例:

在这里插入图片描述
使用javac编译HelloWord,然后使用javap进行一次反编译,其中包含类的基本信息,常量池,类方法定义,
类的基本信息
在这里插入图片描述
常量池:
在这里插入图片描述
类方法定义
在这里插入图片描述
常量池的定义:常量池就是一张表,虚拟机根据这张常量表找到要执行的类名、方法名、参数类型和字面量等信息。

StringTable

StringTable是一个HashTable结构,不能扩容,常量池中的信息都会加载到运行时的常量池中,此时常量池中的符号,还没有变为java字符串对象。
示例:
在这里插入图片描述
字符串拼接:
示例:
在这里插入图片描述
在这里插入图片描述
S4使用在编译期间进行优化,已经在编译期间确定为ab
S5使用StringBuilder动态的配拼接。
StringTable特性:
常量池中字符串仅是符号,第一次使用时才会变成对象。
利用串池的机制,来避免重复创建字符串对象,
字符串变量的拼接原理是StringBuilder。
字符串常量拼接原理是编译器优化。
可以使用interm方法主动将串池中还没有的字符串对象放入串池。

在jdk1.8下,使用interm会将字符串尝试放入串池,如果没有,直接放入串池,如果串池中有,则不会放入串池,会把串池中的对象返回。
在jdk1.6下,使用interm会将字符串尝试放入串池,如果没有,会拷贝一份放入串池,如果没有则不会放入串池,会把串池中的对象返回。
示例:
在这里插入图片描述
第一问为false,s1,s2,s3将“a”,“b”,“ab”都放入到了串池,s4使用StringBuilder进行变量的拼接,s4在堆中,所以返回false。
第二问,s5查询串池中是否含有ab,串池中含有ab,直接引入。返回true。
第三问,s6尝试将ab放入常量池,ab已经在常量池中存在了,返回true。
第四问,x2是堆中的一个对象,x1是常量池中的对象所以返回false。
第五问,如果调转,那么x2会被放入到常量池中,而x1是常量池中的对象,返回true。
第六问,如果为jdk1.6,那么x2放入到常量池中的是x2的拷贝,x2本身还是在堆中,而x1是常量池中的对象,则返回false。
StringTable在jdk1.6中存在于常量池中,
StringTable在jdk1.8中存在于堆中。

直接内存

直接内存常用于NIO操作,分配回收成本较高,读写性能高,不受JVM垃圾回收管理。
文件读写过程:

在这里插入图片描述
直接内存:
在这里插入图片描述
直接内存释放是调用unsafe.freeMemory()方法进行释放,不是通过垃圾回收机制进行内存释放。ByteBuffer的实现类内部使用了虚引用,来检测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,那么就由ReferenceHandler线程通过Clear的clean方法进行释放内存。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值