java_JVM
Posted 偶像java练习生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java_JVM相关的知识,希望对你有一定的参考价值。
JVM 探究
- 请你谈谈你对JVM 虚拟机的理解
- java8 虚拟机和之前的变化更新
- 什么是OOM,什么是栈溢出StackOverFlowError?,怎么分析?
- JVM 常用调优参数有哪些?
- 内存快照如何抓取,怎么分析Dump文件?知道吗?
- 谈谈JVM 中内加载器的认识? rt-jar,ext ,application
1.JVM的位置
建立在操作系统之上
2.JVM的体系结构(自己画一遍)
垃圾回收的位置
3.类加载器
作用: 加载class 文件,如 new Student();->有一个类叫student,而这个类是抽象的,new 玩他他就变成具体的实例了,他的引用在栈里面,具体的人在堆里面
例子:
- 虚拟机自带的加载器
- 启动类(根)加载器
- 扩展类加载器
- 应用程序(系统类)加载器
一直向上找 - 百度:双亲委派机制
package com.kuang.reflection;
public class Car {
public int age;
public static void main(String[] args) {
//类是模板,对象是具体的
Car car1 = new Car();
Car car2 = new Car();
Car car3 = new Car();
car1.age=1;
car2.age=2;
car3.age=3;
System.out.println(car1.hashCode());
System.out.println(car2.hashCode());
System.out.println(car3.hashCode());
Class<? extends Car> aClass1 = car1.getClass();
Class<? extends Car> aClass2 = car2.getClass();
Class<? extends Car> aClass3 = car3.getClass();
System.out.println(aClass1.hashCode());
System.out.println(aClass2.hashCode());
System.out.println(aClass3.hashCode());
ClassLoader classLoader = aClass1.getClassLoader();//AppClassLoader
ClassLoader parent = classLoader.getParent();//ExtClassLoad -> 扩展类加载器
System.out.println(classLoader);
System.out.println(parent);
System.out.println(parent.getParent());//根加载器 //null 1.不存在,2.java 程序获取不到
}
}
输出结果:
1163157884
1956725890
356573597
460141958
460141958
460141958
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@677327b6
null
这个String 的toString 方法不会执行
public class String {
//双亲委派机制: 安全
//1.APP-->EXC --BOOT (向上查找,最终找到根加载器包下的String类)
public String toString(){
return "Hello";
}
public static void main(String[] args) {
String s = new String();
s.toString();
}
4.双亲委派机制
1.类加载器收到类加载的请求 Application
2.将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器
3.启动加载器检查是否能够加载当前这个类,能加载直到结束,使用当前的加载器,否则抛出异常,通知子加载器进项加载
4.重复步骤3
Class not found
null : java 调用不到,或者不存在,调用不到了java 底层是C++ 写的
Java =C+±- 去掉繁琐的东西,指正,内存管理
}
输出结果:
错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application
- 线程级别的东西java 能处理吗,用接口调用本地方法,调用本地方法的修饰符即为native
5.沙箱安全机制
比如核心类:默认 java,javax 包下面的文件,字节码效验器是不会效验的
双亲委派机制:
- 防止恶意代码去干涉善意的代码;
- 他守护了被信任的类库边界
- 他将代码归入保护域,确定了代码可以进行哪些操作
6.Native
1.本地方法接口调用本地方法库,扩展方法的使用。
package com.kuang;
public class Demo {
public static void main(String[] args) {
new Thread(()->{
},"my thread name").start();
}
//native :凡是带了native 关键字的,说明java 的作用范围达不到了,回去调用底层C语言的库!
//会进入本地方法栈,
//调用本地方法接口,JNI
//JNI 的作用:扩展java 类的使用,融合不同的编程语言为java 所用,最初:C,C++。
//Java 单生的时候C,C++ 横行,想要立足,必须要有调用C,C++ 的程序
//他在内存去区域中专门开辟了一块标记区域:Native Method STACK ,登记native 方法
//在最终执行的时候,加载本地方哭中的方法通过JNI
//Java 程序驱动打印机,管理系统,RootBoot 常务即可,在企业级应用中较为少见!
private native void hell0();
//1跨语言获取数据(http,restful,rpc)
//调用其他接口: Socket,WebService,Http ~
//球球爱心网,---> 输入(php)-->NodeJS -->Socket -- C++ 游戏刷爱心
}
JNI 就是本地方法
7.PC寄存器
1. 每次读取下一条指令的时候,计数器就会加1,内存占比非常的小,他是线程私有的
8.方法区
例子如下:
- Jvm 组成,栈,堆,方法区,
- new 一个类的时候,他这里会有一个模板(Test.Class,a,name),右边还有一个常量池(qinjiang),
- 你要把对象(new Test()) 放出来的时候,引用放在栈中,真实的地址放在堆中,然后用引用去指向真实的对象,
9.栈
(喝多了吐就栈,吃多了拉就是队列)
1.栈:数据结构
程序=数据结构+算法:持续学习
程序=框架+业务逻辑~:淘汰!
栈:先进后出,后进先出:桶
1先进,2再进,2先出,1 再出(桶模型)
队列:先进先出(排队嘛)(FIFO:First Input First OutPut)
2先进,1再进,2先出,1 再出
- 为什么main 方法先执行?
- test 运行完了就弹出栈,然后main 方法弹出栈;
- 递归一栈肯定会满了,如下,最终导致栈溢出
栈:栈内存,主管程序的运行,生命周期和线程同步;
线程结束,栈内存也就释放了,对于栈来说,不存在垃圾回收问题
一旦线程结束,栈就Over!
栈:8大基本类型+对象引用+实例的方法;
栈运行原理:栈 帧
栈满了:Exception in thread “main” java.lang.StackOverflowError
Error错误是严重的,只能让虚拟机停下来,异常还是可以捕获的,可以处理的。
栈+ 堆+ 方法区:交互关系
java 的本质是值快递
1.画出一个对象实例化的过程在内存中:百度,看视频
10.三种JVM
- Sun 公司下的 HotSpot
- BEA jRockot
- IBM j9 VM
- 查看虚拟机用的哪个虚拟机java -version
11.堆
1.Heap,一个JVM 只有一个堆内存,堆内存的大小是可以调节的
public static void main(String[] args) {
new Test().test();
}
args 传参。
类加载读取类文件后,一般把什么东西放到堆中?类,方法,常量,变量,保存我们所有引用类型的真实对象。
实对象:
堆内存还要细分位三个区域:
-
新生区(伊甸园去) young/New
-
养老区 old
-
永久区 perm
-
GC 垃圾回收 ,主要是在伊甸园去和养老区-
-
假设内存满了,就会OOM 堆内存不够!java Heap space ,例子如下:
JDK 8以后,永久存储区改了个名字(元空间)
新生区
- 类:诞生和成长的地方,甚至死亡;
- 伊甸园区,所有的对象都生成在伊甸园区,new 出来了(如果生成了10个对象,满了,则会轻GC),如果只有一个活的则会进去幸存区
其他的9个则清空,则剩下的又有10个空间,假如之后幸存0区也满了,假如新生区都满了,则会触发一条重GC,幸存区0 区和1区的能活 下来的则进入养老区,如果养老区重GC Full Gc 10次也满了,即堆内存和养老区满了,则OOM 了,堆溢出。
真理:经过研究,99% 的对象都是临时对象!
12.新生代,老年代
13.永久区
不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:
-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
-XX:MaxMetaspaceSize,最大空间,默认是没有限制的。
除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:
-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
现在我们在 JDK 8下重新运行一下代码段 4,不过这次不再指定 PermSize 和 MaxPermSize。而是指定 MetaSpaceSize 和 MaxMetaSpaceSize的大小。输出结果如下:
这个区域常驻内存的,用来存放JDK 自身携带的Class 对象,inteface 元数据,存储的是java 运行时的一些环境或类信息·,这个区域不存在垃圾回收!关闭JVM 虚拟机就会释放。这个区域的内存。而且出现oom 跟永久代没什么关系。
一个启动类,加载大量的第三方jar 包,tomcat部署了太多应用,或者大量动态生成的反射类,不断的被加载,知道内存满了就会出现oom
- jdk1.6 之前 :永久代,常量池在方法区中。
- jdk1.7 :永久代,但是慢慢退化了,去永久代,常量池在堆中。
- jdk1.8 之后:无永久代,常量池在元空间。
空白最小快:常量池
我们查看选如何设置内存初始化大小:
代码如下:
package com.kuang;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
public class Demo02 {
public static void main(String[] args) {
//返回虚拟机试图使用的最大内存
long max = Runtime.getRuntime().maxMemory();//字节1024*1024
//返回jvm 的初始化总内存
long total =Runtime.getRuntime().totalMemory();
System.out.println("max="+max+"字节\\t"+max/(double)1024/1024+"MB");
System.out.println("total="+max+"字节\\t"+(total/(double)1024/1024)+"MB");
//7.7
//4/1
//64/1
//默认情况下:分配的总内存是电脑内存的1/4,而初始化内存: 1/64
//-Xms1024m -Xmx1024m -XX:+PrintGCDetails
//新生代 + 老年代 =
//305664K +699392K =1005056 =981.5M
//OOM:
//1.先扩大堆内存看结果 -Xms1024m -Xmx1024m -XX:+PrintGCDetails
//2.如果还是不行分析下哪个地方出现了问题(专业工具)
}
}
输出结果
max=1029177344字节 981.5MB
total=1029177344字节 981.5MB
Heap
PSYoungGen total 305664K, used 20971K [0x00000000eab00000, 0x0000000100000000, 0x0000000100000000)
eden space 262144K, 8% used [0x00000000eab00000,0x00000000ebf7afb8,0x00000000fab00000)
from space 43520K, 0% used [0x00000000fd580000,0x00000000fd580000,0x0000000100000000)
to space 43520K, 0% used [0x00000000fab00000,0x00000000fab00000,0x00000000fd580000)
ParOldGen total 699392K, used 0K [0x00000000c0000000, 0x00000000eab00000, 0x00000000eab00000)
object space 699392K, 0% used [0x00000000c0000000,0x00000000c0000000,0x00000000eab00000)
Metaspace used 3197K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 353K, capacity 388K, committed 512K, reserved 1048576K
Process finished with exit code 0
设置参数:
元空间:逻辑上存在,物理上不存在
如果将初始化和最大内存设置8m
package com.UdpClientDemo01;
import java.util.Random;
//-Xms 8m -Xmx8m -XX:+PrintGCDetails
public class psvm {
public static void main(String[] args) {
String str ="kuangshensayjava";
while(true){
str+=str+new Random().nextInt(8888888)+new Random().nextInt(999999999);
}
}
}
输出结果:
[GC (Allocation Failure) [PSYoungGen: 1536K->488K(2048K)] 1536K->668K(7680K), 0.0020638 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1803K->499K(2048K)] 1983K->906K(7680K), 0.0062892 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[GC (Allocation Failure) [PSYoungGen: 2017K->503K(2048K)] 2424K->1038K(7680K), 0.0014230 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1773K->288K(2048K)] 3300K->2310K(7680K), 0.0033247 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1806K->416K(2048K)] 6804K->5414K(7680K), 0.0007959 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) --[PSYoungGen: 1407K->1407K(2048K)] 6406K->6406K(7680K), 0.0008676 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 1407K->0K(2048K)] [ParOldGen: 4998K->2751K(5632K)] 6406K->2751K(7680K), [Metaspace: 3125K->3125K(1056768K)], 0.0034894 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 15K->0K(2048K)] 4750K->4735K(7680K), 0.0004872 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] 4735K->4735K(7680K), 0.0003136 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] [ParOldGen: 4735K->3587K(5632K)] 4735K->3587K(7680K), [Metaspace: 3125K->3125K(1056768K)], 0.0046072 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] 3587K->3587K(7680K), 0.0008857 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] [ParOldGen: 3587K->3570K(5632K)] 3587K->3570K(7680K), [Metaspace: 3125K->3125K(1056768K)], 0.0066249 secs] [Times: user=0.00 sys=0.03, real=0.01 secs]
Heap
PSYoungGen total 2048K, used 92K [0x00000000ffd80000, 0x0000000100000000, 0x0000000100000000)
eden space 1536K, 5% used [0x00000000ffd80000,0x00000000ffd97040,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
to space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
ParOldGen total 5632K, used 3570K [0x00000000ff800000, 0x00000000ffd80000, 0x00000000ffd80000)
object space 5632K, 63% used [0x00000000ff800000,0x00000000ffb7c930,0x00000000ffd80000)
Metaspace used 3158K, capacity 4556K, committed 4864K, reserved 1056768K
class space used 336K, capacity 392K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder微信小程序代码片段