java与c++:
c++:c++对每一个对象即拥有最高权利,也担负着对每个对象什么开始到终结的维护责任
java:在虚拟机的帮助下,不需要对每一个new操作写配对的回收操作,但,一旦出现内存泄露以及内存溢出问题,不了解虚拟机,则很难排查问题。
运行时数据区域分为:
方法区,虚拟机栈,本地方法栈,堆,程序计数器
程序计数器:
可看作是当前线程所执行的字节码的行号指示器。字节码解释器通过改变计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等都需要依赖这个计数器来完成。
程序计数器特点:
1.线程私有(保证切换线程后,能恢复到正确的执行位置)
2.Java虚拟机规范中,唯一一个没有OutOfMemoryError情况的区域
3.生命周期与其线程相同。
Java虚拟机栈
特点:
1.线程私有
2.生命周期与线程相同
3.两种异常:线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError
若虚拟机可动态扩展,且扩展时无法申请到足够的内存,抛出OutOfMemoryError
通常指的“栈”,为虚拟机栈中局部变量表部分
局部变量表包含:基本数据类型、对象引用 和returnAddress(指向一条字节码指令的地址)。
局部变量表所需内存空间在编译期间完成分配。
本地方法栈
与Java虚拟机栈的作用非常相似,也会抛出同样的两种异常。
与Java虚拟机栈的区别:
1.虚拟机栈为虚拟机执行Java方法(字节码)服务
2.本地方法栈为虚拟机使用到的Native方法服务
Java堆
特点:
1.Java虚拟机所管理的内存中最大的一块
2.被所有线程共享,且虚拟机启动时创建
3.几乎所有的对象实例都在这里分配内存
4.GC管理的主要区域
5.若堆中没有内存完成实例分配,且堆也无法再扩展,将抛出OutOfMemoryError异常
方法区(Non-Heap)
特点:
1.各个线程共享的内存区域
2.用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
3.堆的一个逻辑部分,但应将他与堆区分开来
4.并非是永久代,一般类型的卸载时会被回收
5.当方法区无法满足内存分配需求时,抛OutOfMemoryError
运行时常量池: 方法区的一部分
1.存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池存放。
2.存放class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时的常量池中。
3.与class文件常量池相比,它具备动态性。
直接内存(不是虚拟机运行时数据区的一部分,但这部分内存被频繁使用,且可能导致OutOfMemoryError)
特点:
1.本机直接内存的分配不会受到Java堆大小的限制,但会受到本机总内存大小及处理器寻址空间的限制
2.在配置虚拟机参数时,会根据实际内存设置Xmx等参数信息,常忽略直接内存,使各个内存区域总和大于物理内存限制,抛OutOfMemoryError
虚拟机对象的创建
内存分配方式:
1.指针碰撞:前提是java堆中的内存是绝对规整的(即空闲区与已存储区是绝对分开的),那么当内存分配时仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离。
2.空闲列表:java堆的内存并不是规整的,已使用的内存和空闲的内存相互交错,虚拟机就必须维护一个列表,记录上那些内存是可用的,在分配时从列表中找到一块足够大的空间划分给对象 实例,并更新列表上的记录。
执行new指令之后会接着执行<init>方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。
对象的内存布局