Java 内存机制及溢出异常归纳

本文介绍了Java虚拟机管理的内存划分,包括程序计数器、虚拟机栈、本地方法栈、堆、方法区等区域,说明了各区域用途、特点及可能出现的异常。还阐述了Java对象的创建流程、存储结构和访问方式,如创建时的类加载、内存分配等步骤。

在java虚拟中执行java程序时,会把执行过程中所管理的内存划分为若干个不同的数据区,这些数据区分别有不同的用途,java虚拟机所管理的内存会划分为以下几个数据区域:

                                      

下面对着几个区域分别进行详细说明:

1. 程序计数器(Program Counter Register)--线程私有

该区域是一块较小的内存,其可以被看作是当前线程所执行的字节码的行号指示器,字节码解释器就是通过改变计数器的值来读取下一条字节码命令,而且分支,循环,跳转,异常处理,线程恢复等都需要依赖该计数器.一个cpu在同一时间只会处理一个线程中的指令,而为了保证java多线程上下文切换正常,需要每条线程都具有一个独立程序计数器,相互独立,不相影响,因此程序计数器的内存是线程私有的。而且其是唯一一个在java虚拟机规范中没有定义OutOfMemory异常的区域

2. java虚拟机栈(java Virtual Machine Stacks)---线程私有

该部分内存生命周期与线程相同,其描述的是java方法执行的内存模型,方法在执行时会在虚拟机栈中创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出入口等信息,方法在调用到结束时,对应栈帧在虚拟机中入栈和出栈过程。

局部变量表存储编译期可知的基本数据类型(4类8种),对象引用类型和returnAddress(指向一条字节码指令的地址),其中64位长度的long和double类型占用2个局部变量空间,其余数据类型占用1个,局部变量表的内存空间在编译期就已经分配完成,在运行期不会发生改变,该区域存在两种异常:

    1) StackOverflowError异常:线程请求的栈深度大于虚拟机所允许的深度;

    2) OutOfMemoryError异常:当虚拟机栈内存扩展时无法申请到足够的内存;

3. 本地方法栈(Native Method Stack)------线程私有

其与虚拟机栈作用类似,区别是虚拟机栈为java方法进行保障,而本地方法栈是虚拟机使用本地方法进行保障,也会抛出StackOverflowError 和 OutOfMemoryError异常;

4. 堆(java heap)------线程共享

其是虚拟机管理内存中最大的一块,同时也是垃圾回收器管理的主要区域,也称GC堆,在虚拟机启动时创建,用于存放对象实例,所有对象实例和数组内存都在java堆中进行分配,java堆可以位于物理上不连续的内存中,只要逻辑连续即可,其大小在虚拟机中使用参数-Xmx和-Xms来控制,当没有内存在存储对象实例且无法扩展时,抛出OutOfMemoryError异常。

5. 方法区(Method Area)------线程共享

用于存储虚拟机加载的信息:类信息,常量,静态变量,即时编译器编译后代码数据等,在HotSpot虚拟机中,GC分代收集扩展到了方法区,实现类似堆内存的管理,在方法区进行内存回收主要是常量池的回收和对类型的卸载,当无法满足内存分布时,出现OutOfMemoryError异常。

6. 运行时常量池---方法区的一部分

其用于存放编译期生成的各种字面量和符号引用,这些内容将在类加载后进行方法区的常量池中进行存放。

 7. java对象的创建及使用

     1) 对象的创建:正常代码中使用new就可以实现对象的创建,虚拟机在碰到new命令时,在虚拟机中具体流程如下:

         (1) 检查指令参数是否在常量池中存在类的符号引用,并检查该符号引用多代表的类是否被加载,解析和初始化过,如果没                有,首先进行类的加载过程;

         (2) 为新对象分配内存,对象所需的内存大小在类加载后就确定了,其在堆上分配内存有两种方式:指针碰撞(内存被分成                使用和为使用两部分,使用的在一端,未使用的在另一端,这种情况分配内存仅需要将指针进行移动即可)和空闲列表              (此时内存中使用和未使用的空间是不连续的,就需要使用一张列表对未使用的内存进行维护记录),具体使用那种分                 配 方式取决于堆内存的情况以,而堆内存的情况又与使用的垃圾收集器有关;除了内存分配方式,当在并发情况下分配               内存时,可能存在线程不安全的情况,解决的方式有两种:采用CAS配上失败重试机制保证更新操作的原子性;把内存               分配划分到不同的空间进行,即在堆中预先分配一块内存(本地线程分配缓冲TLAB),在线程分配内存时,首先在对应线                 程的TLAB中进行分配,只要在TLAB用完时才需要进行同步锁定;

         (3) 在内存分配结束后,将分配到的内存空间初始化为零;

         (4) 虚拟机对对象进行必要的设置,例如对象时哪个类的实例,如何找到类的元数据信息,对象的哈希码,对象的GC分代                  年龄等等;

          (5) 最后执行初始化方法,为对象分配一些初始化数据

      2) 对象存储结构:包含对象头,实例数据,对其补充三个部分。其中,对象头存储对象自身运行时的数据,以及类型指针               (对 象指向对应类元数据的指针,通过其可以确定对象是哪个类的实例);实例数据存储对象真正有效的信息,即代码中定             义的各种类型的字段数据;对齐补充仅起到占位的作用,因为HotSpot虚拟机规定对象的起始地址必须是8字节的整数倍,           所以当对的实例数据没有对齐时,可以使用对齐补充部分进行补充;

      3)对象的访问:在使用对象时,java需要通过栈上的引用来找到具体对象,其具体访问方式目前常见的有句柄和直接指针两             种:使用句柄时,java堆中首先分配一块内存作为句柄池,对象引用中存储的是对象的句柄地址,对象的句柄地址红包含             对象的实例数据和类型数据各种的地址信息,其好处是在对象发生移动时,仅需要改变对象句柄地址中实例对象的指针即             可;令一种方式是使用直接指针访问,好处是速度快;

下载方式:https://pan.quark.cn/s/a4b39357ea24 布线问题(分支限界算法)是计算机科学和电子工程领域中一个广为人知的议题,它主要探讨如何在印刷电路板上定位两个节点间最短的连接路径。 在这一议题中,电路板被构建为一个包含 n×m 个方格的矩阵,每个方格能够被界定为可通行或不可通行,其核心任务是定位从初始点到最终点的最短路径。 分支限界算法是处理布线问题的一种常用策略。 该算法与回溯法有相似之处,但存在差异,分支限界法仅需获取满足约束条件的一个最优路径,并按照广度优先或最小成本优先的原则来探索解空间树。 树 T 被构建为子集树或排列树,在探索过程中,每个节点仅被赋予一次成为扩展节点的机会,且会一次性生成其全部子节点。 针对布线问题的解决,队列式分支限界法可以被采用。 从起始位置 a 出发,将其设定为首个扩展节点,并将与该扩展节点相邻且可通行的方格加入至活跃节点队列中,将这些方格标记为 1,即从起始方格 a 到这些方格的距离为 1。 随后,从活跃节点队列中提取队首节点作为下一个扩展节点,并将与当前扩展节点相邻且未标记的方格标记为 2,随后将这些方格存入活跃节点队列。 这一过程将持续进行,直至算法探测到目标方格 b 或活跃节点队列为空。 在实现上述算法时,必须定义一个类 Position 来表征电路板上方格的位置,其成员 row 和 col 分别指示方格所在的行和列。 在方格位置上,布线能够沿右、下、左、上四个方向展开。 这四个方向的移动分别被记为 0、1、2、3。 下述表格中,offset[i].row 和 offset[i].col(i=0,1,2,3)分别提供了沿这四个方向前进 1 步相对于当前方格的相对位移。 在 Java 编程语言中,可以使用二维数组...
源码来自:https://pan.quark.cn/s/a4b39357ea24 在VC++开发过程中,对话框(CDialog)作为典型的用户界面组件,承担着与用户进行信息交互的重要角色。 在VS2008SP1的开发环境中,常常需要满足为对话框配置个性化背景图片的需求,以此来优化用户的操作体验。 本案例将系统性地阐述在CDialog框架下如何达成这一功能。 首先,需要在资源设计工具中构建一个新的对话框资源。 具体操作是在Visual Studio平台中,进入资源视图(Resource View)界面,定位到对话框(Dialog)分支,通过右键选择“插入对话框”(Insert Dialog)选项。 完成对话框内控件的布局设计后,对对话框资源进行保存。 随后,将着手进行背景图片的载入工作。 通常有两种主要的技术路径:1. **运用位图控件(CStatic)**:在对话框界面中嵌入一个CStatic控件,并将其属性设置为BST_OWNERDRAW,从而具备自主控制绘制过程的权限。 在对话框的类定义中,需要重写OnPaint()函数,负责调用图片资源并借助CDC对象将其渲染到对话框表面。 此外,必须合理处理WM_CTLCOLORSTATIC消息,确保背景图片的展示不会受到其他界面元素的干扰。 ```cppvoid CMyDialog::OnPaint(){ CPaintDC dc(this); // 生成设备上下文对象 CBitmap bitmap; bitmap.LoadBitmap(IDC_BITMAP_BACKGROUND); // 获取背景图片资源 CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap* pOldBitmap = m...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值