JAVA与C++之间有一堵墙,里面的是要出来 外面的要进去,这一堵墙就是内存动态分配和垃圾收集技术 ,JAVA的程序员在虚拟机的帮助下 ,不再需要为每一个new操作释放,并且不容易出现内存泄露和内存溢出的问题
1,JAVA虚拟机的内存区域;
java虚拟机在执行java程序的过程中会把它所管理的内存分配划分为诺干个不同的区域,这些区域有各自的用途,以及创建和销毁的时间,有的区域会随着虚拟机的启动而存在的 ,有的区域则是依赖用户线程的启动和结束而建立和销毁
内存区域;方法区,JAVA虚拟机栈,本地方法栈,堆,程序计数器组成;
1,1 程序计数器;当前线程所执行的字节码的行号指示器
字节码是指;字节码解释器工作时就是通过改变这个计算器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,等基础功能都需要程序计算器来完成
java虚拟机的多线程是通过线程轮流切换并分配处理器来实现的,一个处理器只会执行一条命令,因此每个线程都需要有一个程序计算器 互不影响 独立存储 我们称为"线程私有"的存储
程序计算机的异常;
程序计算器为null,并且执行方法,这时会抛出一个OutOfMemoryError异常的情况
1,2 java虚拟机栈
每个方法被执行都会创建栈,用于存储局部变量栈,变量栈方法出口等信息,每一个方法从调用到执行完成,对应着从虚拟机的入栈到出栈
特别注意:局部变量表存放了8中基本数据类型 其中double和long是64位长度的数据类型会被占用两个变量空间,其余的占一个
java虚拟机栈的异情况;
a,如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常
b,虚拟机动态扩展是无法申请到足够的内存会抛出OutOfMemoryError异常;
1,3本地方法栈
与java虚拟机栈相似
1,4 java堆
java堆是java虚拟机中最大的一块,java对是被线程共享的一块,在虚拟机启动时,此区域存放的位移目的就是存放对象实例,java所有的对象实例和数组都要在堆上分配
java堆是垃圾收集器的主要区域,很多时候称为"GC堆";分为新生代和老年代
,java堆上可以处于物理上不连续的内存空间,只是逻辑上是连续的即可
java堆异常;
如果在堆内存中没有完成分配会抛出 OutOfMemoryError异常
1,5 方法区
存储的是被虚拟机加载过的类信息,常量,静态变量等数据
方法区异常;
方法区无法满足内存分配时会抛出OutOfMemoryError异常
1,6 运行时常量池
是方法区的一部分,class文件除了类的信息,还有一项信息就是常量池用于存放编译生成的各种字面量和符号
运行时异常
当常量池无法申请到内存分配时会抛出OutOfMemoryError异常
2 ,内存溢出
2,1 java堆溢出
不断的创建对象实例可能会内存溢出异常
//测试程序
//测试堆的类
public class HeapOOM{
staic class oom
{
//静态类
}
public static void main(String[] args) {
List<oom> list = new ArrayList<oom>();
while(true){
list.add(new oom());
}
}
}
2,2虚拟机栈和本地方法栈溢出
方法区无法满足内存分配时会抛出OutOfMemoryError异常
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常
栈分配的越大,越容易产生内存溢出,操作系统分配给每个进程的内存是还有限制的
2,3运行时常量池溢出;
如果运行时想常量池添加内容,String.intern()方法
代码如下;
//测试运行时常量池异常
public class HeapOOM{
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i = 0;
while(true){
list.add(String.valueOf(i++).intern());
}
}
}
当常量池到达一定极限时会抛出异常
运行时常量池溢出与方法区溢出相似