二、JVM对空间大小怎么配置?各区域怎么划?
新生代:短时间生成,可以马上回收
老生代:少部分对象会存在很久,回收策略应不同
三、JVM哪些内存区域会发生内存溢出(程序计数器不会)
OutOfMemoryError
1、栈溢出 虚拟机栈累计,每个线程最多占用1m内存,线程个数越来越多,而且又长时间不销毁
2、堆溢出 堆内存耗尽,对象越来越多,又一直使用,不能被垃圾回收
3、方法区溢出 方法区内存耗尽,加载的类越来越多,很多框架都会在运行期间动态产生新的类。
4、本机直接内存溢出
StackOverflowError 虚拟机栈内部,方法调用次数过多
大部分错误使用死for循环,递归;或者内存本身设置不够,随着接口越写越多,需要修改内存设置。
项目中什么情况会内存溢出,怎么解决的
1、误用线程池导致的内存溢出---------》别自己套用官方的线程池工具创建,自己定义一下有界条件。
2、查询数据量太大导致的内存溢出-----》设置增大内存
3、动态生成类导致的内存溢出----》new对象放里面,如果内存快超出了,它会重新new对象,老的对象会被自动回收,从而规避内存溢出
四、JVM在创建对象采用了哪些并发安全机制?
默认 (本地线程分配缓冲机制)
也可以设置cas+失败重试(乐观锁)
五、为什么不用Finalize
1、执行线程优先级很低
2、只能执行一次
六、jvm内存参数题目
七、java jvm 内存监控软件
软件有很多 java 监视和管理控制台,华为云等自带的控制台
0、上面比较形象可以看出堆、栈、方法区之间的区别,栈存的是局部变量、堆一般是对象等等,而方法区存在的事一些信息加载出来等等,他们互相分工。
1、String a=new String(“fdsdfs”);
堆 存放的是new出来的对象 jvm中只有一个堆区 被所有的线程共享
栈 是变量a 每个栈中的数据私有的 其他栈不能访问。栈中分配的是基本类型和自定义对象的引用。
方法区 是“fdsdfs”;被所有的线程共享,方法区包含所有的class static变量。方法区存放的是类信息和static变量。
2、也可以这么理解:堆是用来存放对象的,栈是用来运行程序的。堆:java的垃圾回收器会自动的回收这些不用的数据。缺点是由于要动态的分配内存,存储效率会比较的慢。
栈:栈的优势是存取效率比较快,仅次于寄存器,栈数据可以共享。但缺点是栈中的数据大小和生存期的固定的,缺乏灵活性。
3、堆和栈的区别可以用如下的比喻来看出:(来自csdn/weixin_41254254)
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就
走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自
由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
————————————————
版权声明:本文为CSDN博主「学习微站公众平台」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43206161/article/details/126918256
OutOfMemoryError
StackOverflowError
InternalError
UnknownError
让我们在本节中详细回顾这些类型。
Java throwable 类层次结构
1.1 OutOfMemoryError
OOM(OutOfMemoryError)在 DevOps 社区中非常流行。 虽然大多数 DevOps 的工程师可能认为只有一种 OutOfMemoryError,但实际上 OutOfMemoryError 有九种不同类型:
java.lang.OutOfMemoryError:在Java 堆空间中创建新的对象
java.lang.OutOfMemoryError:GC 开销超过限制
java.lang.OutOfMemoryError:请求的数组大小超过虚拟机限制,JVM 在为数组分配内存前,会检查要分配的数据结构在系统中是否可寻址,通常为 Integer.MAX_VALUE - 2。
java.lang.OutOfMemoryError:Permgen 空间(Jdk8取消该区域)
java.lang.OutOfMemoryError:Metaspace被用满
java.lang.OutOfMemoryError:无法创建一个新的 native 线程
java.lang.OutOfMemoryError:杀死进程或子进程
java.lang.OutOfMemoryError:超出默认Direct ByteBuffer大小
java.lang.OutOfMemoryError:Out of swap space?
触发每种错误的原因各有不同。类似地,根据 OutOfMemoryError 不同的问题类型,对应的解决方案也不一样。查找OOM触发原因和解决方案,可以参考https://segmentfault.com/a/1190000019910501
通常可以通过分析垃圾回收日志和堆转储文件来诊断和修复 OutOfMemoryError 错误。手动分析垃圾回收日志可能会很乏味,可以考虑使用免费工具,如 GCeasy、HP Jmeter 或 IBM GC analyzer。 类似地,也可以考虑使用 HeapHero 或 Eclipse MAT 这样的免费工具来分析堆转储文件。
1.2 StackOverflowError
线程的堆栈存储了执行的方法、基本数据类型值、局部变量、对象指针和返回值信息,所有这些都会消耗内存。如果线程的堆栈大小超过了内存分配限制,就会抛出 java.lang.StackOverflowError。关于如何调试 StackOverflowError 的细节以及修复这个问题可能的解决方案,可以参考https://jaxenter.com/stackoverflowerror-causes-152027.html
出现StackOverflowError一般有以下两种情况:
方法递归调用问题,导致栈帧不断增加,无法分配新的栈帧(栈容量最小值取决于操作系统内存分页大小)
还有一种情况就是创建线程时,线程所需堆栈大于默认线程堆栈大小,这个时候需要调整参数-Xss
1.3 InternalError
JVM 抛出 java.lang.InternalError 有三个原因,虚拟机软件出现错误、系统软件底层出现错误或者硬件出现故障。
然而,很少会遇到 InternalError 这样的错误。要了解哪些特定情况可能导致 InternalError,请在 Oracle 的 Java Bug 数据库 中搜索 InternalError。在写这篇文章的时候(2018年12月20日),Oracle Java Bug 数据库中仅报告了200个 InternalError,而且大多数都已经修复了,所以不必对此过于担心。
1.4 UnknownError
当发生异常或错误,但 Java 虚拟机无法报告确切的异常或错误时,就会抛出 java.lang.UnknownError。UnknownError 很少出现。事实上,在 Oracle Java Bug 数据库中搜索 UnknownError 时,只找到了2个 Bug。参见:远程调试 Java 应用程序
非受检异常(Unchecked exceptions)
同步模式与异步模式
让我们在本节中讨论这两个特征。
2.1 非受检异常
有两种异常类型:受检异常和非受检异常。
在编译时检查的异常称为受检异常。如果代码中的某些方法抛出受检异常,那么该方法必须处理该异常或者使用 throws 关键字指定异常。受检异常包括 IOException、SQLException、DataAccessException、ClassNotFoundException 等。
非受检异常常没有这个要求,它们不需要捕获或者声明抛出。所有类型的 VirtualMachineError 都是非受检异常。
2.2 同步模式与异步模式
可以在两种模式下抛出异常:同步模式和异步模式。
同步异常在特定程序语句执行时发生,无论该程序在类似的环境中执行了多少次。同步异常的例子有 NullPointerException、 ArrayIndexOutOfBoundException 等。
异步异常可以在任何时间点和程序语句的任何部分发生,异常抛出的地方也不一样。所有的 VirtualMachineError 都是异步抛出的,但有时也会同步抛出。StackOverflowError 可能随方法调用而同步抛出,也可能随着本地方法执行或 Java 虚拟机资源限制异步抛出。类似地,OutOfMemoryError 可能在对象创建、数组创建、类初始化和装箱转换时同步或异步抛出。
————————————————
版权声明:本文为CSDN博主「testunit」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/testunit/article/details/103971820
类加载子系统
负责从文件系统或是网络中加载class信息,加载的信息存放在一个称之为方法区的内存空间
方法区
用于存放类的信息、常量信息、常量池信息、包括字符串字面量和数字常量。我们常用的反射就是从这个方法区里读取的类信息
Java堆
堆空间是jvm启动的时候创建的一块内存区域,几乎所有的对象实例都放在这个空间里(可以理解成new 出来的那些对象)。
这个区域被划分为新生代和老年的,之后重点讲解,我们常说的GC垃圾回收机制,就是主要回收堆空间的垃圾数据。
堆空间里的数据,是被所有线程共享的,所以会存在线程安全的问题。所以那些锁就是为了解决堆空间数据线程安全的问题而生的。
直接内存
直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但这部分也是被频繁的读写使用,也可能会导致OutOfMemoryError异常的出现。
Java的NIO中的allocateDirect方法是可以直接使用直接内存的,能显著的提高读写的速度。
Java栈
就是我们常说的堆栈两兄弟之一的栈,所有线程共享堆空间里的数据,但是栈空间是每个线程独有的,互相直接不能访问。
栈空间是线程创建的时候所创建的一份内存空间,栈里主要保存一些局部变量、方法参数、Java方法调用,返回值等信息。
本地方法栈
本地方法栈和Java栈不同之处在于,可以直接调用Java本地方法,即JDK中用native修饰的方法。
垃圾收集系统
GC垃圾回收,是一个非常重要的知识点,保证我们程序能够有足够的内存空间运行,回收掉内存中已经无效的数据,大家就可以理解成我们日常中活中的垃圾回收。
回收算法一般有标记清除算法、复制算法、标记整理算法等等,之后的文章,我们会详解讲解每一种算法。
PC寄存器
它是每个线程私有的空间,JVM会为每个线程创建单独的PC寄存器,在任意时刻,一个Java线程总是在执行一个方法,这个方法被称为当前方法,如果当前方法不是本地方法,PC寄存器会执行当前正在被执行的指令,如果是本地方法,则PC寄存器值为undefined,寄存器存放如当前环境指针、程序计数器、操作栈指针、计算的变量指针等信息。
执行引擎
是jvm非常核心的组件,它负责执行jvm的字节码,一般先会编译成机器码后执行。
类加载机制
jvm的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由jvm的具体实现指定的。[来自官方规范]
jvm组成结构之一就是类装载器子系统,我们今天就来仔细讲讲这个组件。