栈是一种数据结构。程序=数据结构+算法
栈:先进后出,后进先出
队列:先进先出(FIFO)
Q:为什么main()方法先执行后结束
A:先进栈,最后出
Oracle关于栈和栈帧提供了如下描述:
每个JVM线程拥有一个私有的 Java虚拟机栈,创建线程的同时栈也被创建。一个JVM栈由许多帧组成,称之为"栈帧"。JVM中的栈和C等常见语言中的栈比较类似,都用于保存局部变量和部分计算结果,同时也参与方法调用和返回。
如Oracle官方说明,每个线程拥有自己的私有栈,因此在多线程应用中将有多个栈,每个栈有自己的栈帧。
栈内存,主管程序的运行,生命周期和线程同步
线程结束,栈内存释放了,对于栈来说,不存在垃圾回收,一旦线程结束,栈就Over了!
栈:8大基本类型 + 对象的引用 + 实例的方法
栈满了:StackOverflowError
一个JVM只有一个堆内存,堆内存的大小是可以调节的,我们可以通过选项"-Xmx"和"-Xms"来进行设置。一旦堆区中的内存大小超过“-xmx"所指定的最大内存时,将会抛出**outofMemoryError(OOM)**异常。
**Q:**类加载器读取类文件后,一般会把什么东西放到堆中?
**A:**类,方法,常量,变量~保存我们所有引用类型的真实对象
堆内存中还要细分为三个区域:
GC垃圾回收主要是在伊甸园区和养老区
年轻代又分为Eden和Survivor区。Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例是8:1:1。
经过研究,99%的对象都是临时对象!
新生区的幸存者经过多次存入养老区
这个区域是常驻内存的。用来存放JDK自身携带的Class对象。Interface元数据,存储的是Java运行时的一些环境。这个区域不存在垃圾回收!关闭虚拟机就会释放这个区域的内存。
一个启动类加载了大量的第三方jar包。Tomcat部署了太多应用,大量动态生成的反射类。不断被加载,知道内存满就会出现OOM;
但是,元空间:逻辑上存在,物理上不存在!
package com.draco.heapOverflow;
/**
* 元空间逻辑上存在,物理上不存在
*/
public class SanQu {
public static void main(String[] args) {
// 返回jvm试图使用的最大内存
long max = Runtime.getRuntime().maxMemory();
// 返回jvm的初始化内存
long total = Runtime.getRuntime().totalMemory();
System.out.println("max="+max+"字节 "+(max/(1024*1024))+"MB");
System.out.println("total="+total+"字节 "+(total/(1024*1024))+"MB");
//默认情况下,试图分配的最大内存是电脑内存的1/4,而初始化的内存是1/64
// -Xms1024m -Xmx1024m -XX:+PrintGCDetails
}
}
运行结果:
当修改了VM选项后:-Xms1024m -Xmx1024m -XX:+PrintGCDetails
,输出结果:
让我们来算一笔账,
新生区:305664k;养老区:699392k
加在一起:1,005,056k,除以1024后 = 981.5MB,等于jvm试图分配的最大内存,所以说元空间逻辑上存在,物理上不存在。
尝试扩大堆内存去查看内存结果
-Xms1024m -Xmx1024m -XX:+PrintGCDetails
若不行,分析内存,看一下是哪个地方出现了问题(专业工具)
MAT,Jprofiler作用:
-Xms 设置初始化内存分配大小,默认1/64
-Xmx 设置最大分配内存,默认1/4
-XX:+PrintGCDetails 打印GC垃圾回收信息
-XX:+HeapDumpOnOutOfMemoryError 生成oomDump文件
-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
-Xms1024m -Xmx1024m -XX:+PrintGCDetails