Java 虚拟机

运行时数据区域
 

方法区:方法区是线程共享的,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。

虚拟机栈:虚拟机栈是线程私有的,其生命周期与线程相同即每个线程下都有一个虚拟机栈,每个方法在执行前都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等。每一个方法从调用到完成就对应着一个栈帧入栈到出栈的过程。

本地方法栈:作用类似于虚拟机栈,虚拟机栈为虚拟机执行java方法服务,而本地方法栈则是为虚拟机使用到的Native方法服务。本地方法栈也可以抛出StackOverflowError和OOM异常;

堆(java堆):java堆是java虚拟机所管理的内存中最大的一块,其也是线程共享的。用于存储对象的实例,所有的对象实例和数组都需要在堆上分配,但是随着JIT编译器的发展与逃逸分析技术成熟,栈上分配,标量替换优化技术将会导致一些微秒的变化发生,所有的对象都分配在堆上也渐渐变得不那么绝对了。

程序计数器:用于计数,标记当前执行到哪一行代码,线程私有。

GC回收算法
 

1、标记-清除算法(最基础的算法) 经过一次标记后同一清楚内存会产生很多碎片内存,可能会导致存储大文件时,找不到一块连续的内存来进行存储,需要再次回收。

2、复制算法 实现简单,运行高效,但是会占用一半内存,但是就不用再考虑碎片内存了。但是很多公司用这种方式回收新生代,将内存划分为Eden和Survivor空间,比例8比1.当回收时将Eden和Survivor中还存活的对象放入另一半的Survivor中,当然Survivor中内存不够时依赖其他内存(老年代)进行分配担保,这就是内存的分配担保。这样也就不会浪费一般的空间了浪费掉最多10%的内存空间。其根本就是将内存划分为一份Eden空间和两份Survivor空间,其中一份Survivor空间用作复制使用。

3、标记整理算法 标记整理算法和标记清除一样,但是后续不是直接清理回收对象,而是让存活的对象向一端移动,然后直接清除掉端边界以外的内存。

4、分代收集算法  根据对象存活周期的不同将内存划分几块,一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象的存活率高,没有额外空间对它进行分配担保,就必须使用‘标记-清理’或者‘标记-整理’算法进行回收。

Android-Dalvik虚拟机GC回收
 

Dalvik虚拟机用来分配对象的堆划分为两部分,一部分叫做Active Heap,另一部分叫做Zygote Heap。下面基于管理机制来介绍为何分配为这两部分,以及堆内存的管理。

  Android系统启动后,会有一个Zygote进程创建第一个Dalvik虚拟机,它只维护了一个堆。以后启动的所有应用程序进程是被Zygote进程fork出来的,并都持有一个自己的Dalvik虚拟机。在创建应用程序的过程中,Dalvik虚拟机采用COW策略复制Zygote进程的地址空间。

  COW策略:一开始的时候(未复制Zygote进程的地址空间的时候),应用程序进程和Zygote进程共享了同一个用来分配对象的堆。当Zygote进程或者应用程序进程对该堆进行写操作时,内核就会执行真正的拷贝操作,使得Zygote进程和应用程序进程分别拥有自己的一份拷贝,这就是所谓的COW。因为copy是十分耗时的,所以必须尽量避免copy或者尽量少的copy。

  为了实现这个目的,当创建第一个应用程序进程时,会将已经使用了的那部分堆内存划分为一部分,还没有使用的堆内存划分为另外一部分。前者就称为Zygote堆,后者就称为Active堆。这样只需把zygote堆中的内容复制给应用程序进程就可以了。以后无论是Zygote进程,还是应用程序进程,当它们需要分配对象的时候,都在Active堆上进行。这样就可以使得Zygote堆尽可能少地被执行写操作,因而就可以减少执行写时拷贝的操作。在Zygote堆里面分配的对象其实主要就是Zygote进程在启动过程中预加载的类、资源和对象了。这意味着这些预加载的类、资源和对象可以在Zygote进程和应用程序进程中做到长期共享。这样既能减少拷贝操作,还能减少对内存的需求。

  类似于JVM,Dalvik虚拟机也需要负责对堆内存中的对象进行管理工作,它使用的也是标记清除算法,但是细节上略有区别。

  Mark-Sweep算法分为两个阶段:

    Mark阶段:通过递归对象的引用,从对象的根集开始标记被引用的对象。

    Sweep阶段:回收没有被标记的对象占用的内存。

  Dalvik虚拟机通过Heap Bitmap来标记标记对象有没有被引用。所谓Heap Bitmap就是一个unsigned long数组,如果一个对象被引用,那么在Bitmap中与它对应的那一位就会被设置为1。否则的话,就设置为0。Dalvik使用了两个Bitmap来描述堆的对象,一个称为Live Bitmap,另一个称为Mark Bitmap。Live Bitmap用来标记上一次GC时被引用的对象,也就是没有被回收的对象,而Mark Bitmap用来标记当前GC有被引用的对象。这样只需要回收上一次被引用,当前未被引用的对象就可以了。

  在垃圾收集的Mark阶段,要求除了垃圾收集线程之外,其它的线程都停止(Stop The World),否则如果对象在GC过程中又引用了其他对象,就会可能导致不能正确地标记每一个对象。然而,这将造成程序卡顿,效率降低。所以必须允许在Mark阶段使垃圾回收线程和其他线程可以并发执行(Concurrent GC)。

为了实现此目的,Dalvik将Mark阶段划分为两步:

    第一步,只标记根集对象,即在GC过程开始的时刻,那些被全局变量,栈变量,寄存器对象引用的对象。这个阶段只允许GC线程运行,防止这些根集对象在这个过程中再去引用其他对象。

     第二步,通过这些根集对象引用关系,可以找到并标记其他正在使用的对象。这个阶段可以允许其他线程与GC线程并发执行。为了实现GC线程与其他线程并发,需要把其他线程对对象的修改记录下来,记录这些修改的数据结构被称为Card Table。

  Dalvik虚拟机进行部分垃圾收集时,实际上就是只收集在Active堆上分配的对象。因此对Dalvik虚拟机来说,Card Table就是用来记录在Zygote堆上分配的对象在部收垃圾收集执行过程中对在Active堆上分配的对象的引用。

  与Bitmap不同,Card Table中每个card大小为一个字节,如果与它对应的对象在第二步未被修改过,其值为clean,否则为dirty。对于被修改过的对象,在第二步结束后需要重新使用GC线程排他地对这些对象进行标记。由于这些对象不是很多所以这个过程很快,这也是分两步的原因。

 
OutOfMemoryError异常
 

方法区在无法满足内存分配时会抛出OutOfMemoryError异常

。运行时常量池也是方法区的一部分当常量池无法再申请到内存时会抛出OutOfMemoryError异常。

直接内存,不受java堆大小的限制,但是受到本机总内存大小及处理器寻址限制,当各个内存区域总和大于物理内存限制时抛出OutOfMemoryError异常。

new其实只是申请了空间,之后会接着执行<init>方法,这样才算真正产生了一个对象。

java主流虚拟机并没有使用引用计数的方式来进行回收判断,因为这种方式无法处理循环引用的情况。

java一般使用根节点可达性分析来实现回收判断,判断对象是否存活。

引用方式
java引用的四种方式:强引用,软引用,弱引用,虚引用。

强引用:Object obj = new Object()这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。

软引用:用来描述一些还有用但并非必须的对象,对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。

弱引用:弱引用也是用来描述非必要对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。

虚引用:也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对生存时间构成影响,也无法通过虚引用来取得一个对象实例,为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统的通知。

可达性分析后,对象不会立即被回收,需要在标记两次后才会被回收。

在垃圾回收时,任何一个对象的finalize方法都只会被系统自动调用一次,可以实现一次自我救赎,不建议使用。

类回收的三个必要条件:

1、该类的所有实例已经被回收,也就是java堆中不存在该类的任何实例

2、加载该类的ClassLoader已经被回收

3、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/623045.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSC8021_computer network_The Transport Layer

Role of the transport layer • The transport layer is responsible for providing a reliable end-to-end connection between two application processes in a network • Abstracting away the physical subnet • Does not involve intermediate nodes • Takes a netwo…

UML-通信图和交互概览图(通信图和顺序图的区别与联系)

UML-通信图和交互概览图&#xff08;通信图和顺序图的区别与联系&#xff09; 一、通信图简介1.消息2.链接 二、通信图和[顺序图](https://blog.csdn.net/weixin_65032328/article/details/135587782)的联系与区别三、交互概览图四、顺序图转化为通信图练习 一、通信图简介 通…

2.2 物理层

2.2 物理层 2.2.1 物理层的基本概念 1、物理层主要解决在各种传输媒体上传输比特0和1的问题&#xff0c;进而给数据链路层提供透明传输比特流的服务 2、由于传输媒体的种类太多&#xff08;例如同轴电缆、光纤、无线电波等&#xff09;&#xff0c;物理连接方式也有很多例如…

vs c++ qt 打包成exe

1 vs2019QT 打包项目 可执行文件exe_哔哩哔哩_bilibili 2 在开始中 找到 qt5142\5.14.2\msvc2017_64 类似于cmd命令行 3 windeployqt.exe 形态环境变量 qt安装包搜索windeployqt.exe D:\qt\5.15.2\winrt_x64_msvc2019\bin 4 \x64\Release\ vs调到Release x64 重新生成 5 运…

libcurl开源库的编译与使用全攻略

libcurl简介 libcurl 是一个广泛使用的、支持多种协议的、开源的客户端URL传输库&#xff0c;提供了许多用于数据传输的API&#xff0c;例如文件传输、FTP、HTTP、HTTPS、SMTP等。libcurl 的主要特点包括 支持多种协议&#xff1a;libcurl 支持多种协议&#xff0c;如 HTTP、F…

Spring集成

目录 概述1 声朋一个简单的集成流1.1 使用XML定义集成流1.2 使用Java配置集成流1.3 使用Spring lntegration 的 DSL 配置 2 Spring integration 功能概览2.1 消息通道2.2 过滤器2.3 转换器2.4 路由器2.5 切分器2.6 服务激活器2.7 网关2.8 通道适配器2.9 端点模块 概述 就像我们…

JDK8-JDK17版本升级

局部变量类型推断 switch表达式 文本块 Records 记录Records是添加到 Java 14 的一项新功能。它允许你创建用于存储数据的类。它类似于 POJO 类&#xff0c;但代码少得多&#xff1b;大多数开发人员使用 Lombok 生成 POJO 类&#xff0c;但是有了记录&#xff0c;你就不需要使…

逸学Docker【java工程师基础】3.1安装Jenkins

1.下载镜像 docker pull jenkins/jenkins:lts 2.运行容器 docker run -d -u root -p 8080:8080 -p 50000:50000 -v /var/jenkins_home:/var/jenkins_home -v /etc/localtime:/etc/localtime --name jenkins jenkins/jenkins:lts 3.要启动名为 jenkins 的 Docker 容器 docker st…

HarmonyOS-LocalStorage:页面级UI状态存储

管理应用拥有的状态概述 上一个章节中介绍的装饰器仅能在页面内&#xff0c;即一个组件树上共享状态变量。如果开发者要实现应用级的&#xff0c;或者多个页面的状态数据共享&#xff0c;就需要用到应用级别的状态管理的概念。ArkTS根据不同特性&#xff0c;提供了多种应用状态…

OpenGauss源码分析-SQL引擎

所讨论文件大多位于src\common\backend\parser文件夹下 总流程 start_xact_command()&#xff1a;开始一个事务。pg_parse_query()&#xff1a;对查询语句进行词法和语法分析&#xff0c;生成一个或者多个初始的语法分析树。进入foreach (parsetree_item, parsetree_list)循环…

LeetCode 每日一题 Day 37-43

终于考完试了&#xff0c;寒假期间将会每天持续更新&#xff01; 447. 回旋镖的数量(Day 37) 给定平面上 n 对 互不相同 的点 points &#xff0c;其中 points[i] [xi, yi] 。回旋镖 是由点 (i, j, k) 表示的元组 &#xff0c;其中 i 和 j 之间的欧式距离和 i 和 k 之间的欧…

Ai网站收藏,备注

ai网站 有良心的up会留下地址&#xff1a; 1.【codeformer】https://replicate.com/sczhou/codeformer&#xff08;在线版&#xff09;&#xff1b;https://pan.baidu.com/s/1L9m6YS9w3oOaywjUncaNyw?pwdiw8f&#xff08;本地版&#xff0c;4个G&#xff09; 2.【Magisto】&a…

通过开源端点可见性改善网络安全响应

在当今复杂的数字环境中&#xff0c;企业内的许多不同端点&#xff08;从数据中心的服务器到咖啡店的笔记本电脑&#xff09;创建了巨大且多样化的攻击面。每个设备都存在网络安全威胁的机会&#xff0c;每个设备都有其独特的特征和复杂性。攻击者使用的多种攻击媒介不仅是一个…

正则表达式中的“回引用(回溯)”——别名引用与序号引用的差异及正则表达式中的“P”关键字

读到一段巧妙的正则表达式&#xff0c;勾起我对正则表达式欠缺知识点的探寻&#xff1a; P y t h o n Python Python正则表达式中的“回引用(回溯)”——分组别名引用与序号引用的差异及正则表达式中的“P”关键字详情。 (笔记模板由python脚本于2024年01月14日 07:49:35创建&a…

pytorch集智4-情绪分类器

1 目标 从中文文本中识别出句子里的情绪。和上一章节单车预测回归问题相比&#xff0c;这个问题是分类问题&#xff0c;不是回归问题 2 神经网络分类器 2.1 如何用神经网络分类 第二章节用torch.nn.Sequantial做的回归预测器&#xff0c;输出神经元只有一个。分类器和其区别…

第九部分 使用函数 (三)

目录 一、文件名操作函数 1、dir 2、notdir 3、suffix 4、basename 5、addsuffix 6、addprefix 7、join 一、文件名操作函数 下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是 一系列的文件名来对待。 1、dir $(dir <names..>…

QT——connect的第五个参数 Qt::ConnectionType (及qt和c++的多线程的区别)

一直对QT的多线程和c的多线程的区别有疑惑&#xff0c;直到看到文档中这一部分内容才豁然开朗 一.ConnectionType参数的类型和区别 首先是官方文档中对于该枚举值的区别介绍&#xff1a; 对于队列&#xff08;queued &#xff09;连接&#xff0c;参数必须是 Qt 元对象系统已知…

强化学习应用(四):基于Q-learning的物流配送路径规划研究(提供Python代码)

一、Q-learning算法简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于马尔可夫决策过程&#xff08;MDP&#xff09;的问题。它通过学习一个值函数来指导智能体在环境中做出决策&#xff0c;以最大化累积奖励。 Q-learning算法的核心思想是使用一个Q值函数来估计每…

边缘计算:挑战与机遇并存

边缘计算&#xff1a;挑战与机遇并存 在数字化时代&#xff0c;数据成为了驱动创新和经济增长的关键要素。然而&#xff0c;随着数据的不断增长&#xff0c;传统的集中式计算模式已经难以满足实时处理和分析的需求。边缘计算作为一种新兴的计算模式&#xff0c;通过将数据处理…

el-table 可编辑表格大数据渲染性能优化

背景与分析 可编辑表格&#xff1a;是指表格单元格是一个form表单元素&#xff0c;或者有可能会变成表单元素。 1、不可分页的表格&#xff0c;大数据渲染 当数据量足够大时&#xff0c;比如说1000条数据&#xff0c;页面渲染就会卡死&#xff0c;需要卡5s到10s&#xff0c;才…