c语言内存怎么回收和代码是什么?

c语言内存怎么回收和代码是什么?,第1张

在C语言中,使用malloc来动态申请内存,申请完后必须释放该空间。如果不手动释放,那么只能等程序运行结束后系统去回收,但在程序运行过程中容易造成内存溢出的问题,所以应该使用free(void*)来手动释放申请的空间,这样可以保证程序的健壮性。案例如下:\x0d\x0a#include "stdio.h"\x0d\x0a#include "stdlib.h"\x0d\x0a#include "string.h"\x0d\x0avoid main()\x0d\x0a{\x0d\x0a //申请20个字节空间\x0d\x0a char *str = (char*)malloc(20)\x0d\x0a //将空间内容设置为\0\x0d\x0a memset(str, '\0', 20)\x0d\x0a //为每个字节空间赋值\x0d\x0a char *p = str\x0d\x0a for (int i = 0i 回答于 2022-11-16

本文主要内容

本文主要从概念上介绍内存回收及垃圾收集器相关内容,不涉及具体性能调优。

内存回收是程序员永恒的主题,虽然Java虚拟机自动回收内存,但仍存在内存漏泄的可能,需要理解内存回收机制,有助于程序员规避、排查内存泄漏问题。

GC机制,最重要的是三个问题:

对象已死

对象是否已经死亡,可被回收,经常能听到下面这种说法:

引用计数法 :给对象中添加一个引用计数器,每当有一个地方引用时,计数器就加1,当引用失效时,计数器值就减1,任何时候计数器为0的对象就是不可能再被使用的

不过,它存在一个致命缺陷,很难解决循环引用问题,比如对象AB,A引用B,B也引用A,但它们再没有被其它人所引用,AB理应是被回收对象,但它们的引用计数器仍然不为0,导致无法回收。

Java虚拟机不使用此算法来判定对象是否死亡,不过它依然有很多优点,简单。Android 中的智能指针即是使用这种方法,不过添加了智能指针强弱引用来解决循环引用问题

可达性分析算法 ,这个算法的基本思路就是通过一系列的名为“GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到“GC Roots"没有任何引用链相连,则此对象不可用,将被回收

在Java中,可作为“GC Roots"的对象包括以下几种:

引用

在JDK1.2以前,引用的概念为:

JDK1.2之后,引用概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用四种,四种引用强度依次减弱。

垃圾收集算法

本章将介绍三种垃圾收集算法。

标记清除算法 ,算法分成“标记”和“清除”两个阶段,首先标记出需要回收的对象,在标记完成后统一回收掉所有被标记的对象

它主要有两个问题,一是效率不高,标记和清除过程的效率都不高,另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多,当程序在运行中需要分配较大对象,因为碎片过多,可能无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作

复制算法 ,为了解决效率问题,一种称为复制的收集算法出现了。它将内存按容量划分为大小相等的两块,每次只使用其中的一块,当这一块内存使用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。每次都是只对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是代价高昂,将内存缩小为原来的一半。

现在的商业虚拟机都采用这种算法来回收新生代,新生代中的对象98%是朝生夕死的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,当回收时,将Eden和Survivor看还存活的对象一次性拷贝到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。

虚拟机默认Eden和Survivor的大小比例是8比1,所以只有10%的空间会被浪费。

如果存活的对象较多而Survivor空间不够用时,需要依赖其它内存(老年代)进行分配担保,如果另外一块Survivor空间没有足够的空间来存放上一次新生代的存活对象,这些对象将直接通过分配担保机制进入老年代

标记整理算法 ,复制收集算法在对象存活率较高时就要执行较多的复制 *** 作,效率将会变得更低,更关键的是,如果不想浪费一半的空间,就需要额外的空间进行分配担保,以应对所有对象百分百存活的极端情况。所以老年代一般不直接使用这种算法

根据老年代的特点,提出了“标记整理算法”,过程依然和“标记清除算法”一致,但后续步骤不是直接对可回收对象进行清除,而是让所有存活对象都向一端移动,然后直接清理掉边界以外的内存。

分代收集算法

当前商业虚拟机的垃圾收集都采用分代收集算法。它根据对象存活周期的不同将内存划分为几块。

一般是把Java堆分成新生代和老年代,新生代又分成一块较大的Eden和两块Survivor。根据各个年代的特点采用最适当的收集算法。

在新生代中,每次垃圾回收时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率罗高,没有额外空间对它进行分配担保,就必须使用标记清理或者标记整理算法。

垃圾收集器

Serial收集器

Serial收集器是最基本、历史最悠久的收集器。顾名思义,这个收集器是一个单线程收集器。单线程的意义并不仅仅说明它只会使用一个CPU或者一条线程去完成垃圾收集工作,更重要的是它在垃圾收集时,必须暂停其他所有的工作线程(Sun将这件事情称之为“Stop the world”),直到它结束

“Stop the world”,非常影响用户体验,虚拟机在后台自动发起和完成的,在用户不可见的情况下把用户的正常工作的线程全部停掉。

虽然Serial收集器出现时间较长,但它依然是Client模式下的默认新生代收集器

ParNew收集器

ParNew收集器其实就是Serial收集器的多线程控制版本,除了使用多条线程进行垃圾收集之外,其它和Serial收集器完全一样。

ParNew收集器是Server模式下虚拟机中的首选的新生代收集器。而且在单CPU环境下,ParNew绝对不会比Serial更高效,甚至由于存在线程交互的开销,在两个CPU的环境中都不一定比Serial更好

Parallel Scavenge收集器

Parallel Scavenge收集器也是一个新生代收集器,它也是使用复制算法,又是并行的多线程收集器,看上去和ParNew一样,但它非常的有特点。

Parallel Scavenge收集器关注点即是吞吐量,CMS等收集器的关注点是尽量缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge的目的则是达到一个可控制的吞吐量。

Parallel Scavenge提供两个参数用于精准控制吞吐量

Serial old收集器

Serial old收集器是Serial收集器的老年代版本,同样是一个单线程收集器,使用标记整理算法,它的主要意义也是被Client模式下的虚拟机使用

Parallel old收集器

Parallel old是Parallel Scavenge收集器的老年代版本,使用多线程和标记整理算法。

CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,它很适合互联网站或者B/S系统的服务端上。

从Mark Sweep名字可知,CMS用的是标记清除算法,它的动作过程较之前的复杂一些,整个过程分为4个步骤:

其中初始标记、重新标记这两个步骤仍然需要 “Stop the world”。初始标记只是标记一下GC Roots能直接关联到的对象,速度很快,并发阶段就是进行GC Root Tracing的过程,而重新标记则是为了修正并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,重新标记时间略比初始标记长,但远比并发标记时间短。

整个过程最耗时的是并发标记和并发清除,但用户线程和收集器线程一起工作,所以总体上说,CMS收集器的内存回收过程是与用户线程一起并发地执行。

Java语言引入了Java虚拟机 具有跨平台运行的功能 能够很好地适应各种Web应用 同时 为了提高Java语言的性能和健壮性 还引入了如垃圾回收机制等新功能 通过这些改进让Java具有其独特的工作原理

.Java虚拟机

Java虚拟机(Java Virtual Machine JVM)是软件模拟的计算机 它可以在任何处理器上(无论是在计算机中还是在其他电子设备中)安全兼容地执行保存在 class文件中的字节码 Java虚拟机的 机器码 保存在 class文件中 有时也可以称之为字节码文件

Java程序的跨平台特性主要是指字节码文件可以在任何具有Java虚拟机的计算机或者电子设备上运行 Java虚拟机中的Java解释器负责将字节码文件解释成为特定的机器码进行运行 因此在运行时 Java源程序需要通过编译器编译成为 class文件

Java虚拟机的建立需要针对不同的软硬件平台来实现 既要考虑处理器的型号 也要考虑 *** 作系统的种类 由此在SPARC结构 X 结构 MIPS和PPC等嵌入式处理芯片上 在UNIX Linux Windows和部分实时 *** 作系统上都可实现Java虚拟机

.无用内存自动回收机制

在程序的执行过程中 部分内存在使用过后就处于废弃状态 如果不及时进行回收 很有可能会导致内存泄漏 进而引发系统崩溃 在C++语言中是由程序员进行内存回收的 程序员需要在编写程序时把不再使用的对象内存释放掉 这种人为管理内存释放的方法往往由于程序员的疏忽而致使内存无法回收 同时也增加了程序员的工作量 而在Java运行环境中 始终存在着一个系统级的线程 专门跟踪内存的使用情况 定期检测出不再使用的内存 并自动进行回收 避免了内存的泄露 也减轻了程序员的工作量

.代码安全性检查机制

安全和方便总是相对矛盾的 Java编程语言的出现使得客户端计算机可以方便地从网络上上传或下载Java程序到本地计算机上运行 但是如何保证该Java程序不携带病毒或者没有其他危险目的呢?为了确保Java程序执行的安全性 Java语言通过Applet程序来控制非法程序的安全性 也就是有了它才确保Java语言的生存

Java字节码的执行需要经过以下 个步骤

( )由类装载器(class loader)负责把类文件( class文件)加载到Java虚拟机中 在此过程需要检验该类文件是否符合类文件规范

( )字节码校验器(bytecode verifier)检查该类文件的代码中是否存在着某些非法 *** 作 例如Applet程序中写本地计算机文件系统的 *** 作

( )如果字节码校验器检验通过 由Java解释器负责把该类文件解释成为机器码进行执行

注意

Java虚拟机采用 沙箱 运行模式 即把Java程序的代码和数据都限制在一定内存空间里执行 不允许程序访问该内存空间以外的内存 如果是Applet程序 还不允许访问客户端机器的文件系统

Java的运行环境

无论哪种语言都需要有它特定的运行环境 也就是平台 Java语言同样不例外 但是如何理解Java程序与硬件环境无关呢?

几乎所有的语言都需要通过编译或者解释才可以被计算机执行 但是Java有一点不同 它同时需要这两个过程 其实 也正是因为这个原因才使Java这种语言具有了平台无关性 当完成一个Java源程序后 首先 通过Java翻译程序将它编译成一种叫做字节码的中间代码 然后再由Java平台的解释器将它转换成为机器语言来执行 这一平台的核心就是JVM

Java的编译过程与其他的语言不同 像C++这样的语言 在编译时它是与计算机的硬件平台信息密不可分的 编译程序通过查表将所有指令的 *** 作数和 *** 作码等转换成内存的偏移量 即程序运行时的内存分配方式 目的是保证程序正常运行 而Java却是将指令转换成为一种 class的文件 这种文件不包含硬件的信息 需要执行时只要经过安装有JVM的机器进行解释 创建内存分配后再通过查表来确定一条指令所在的地址 这样就有效地保证了Java的可移植性和安全性

Java平台具有这样的特性和它的结构有关 通常一个程序运行的平台是一个硬件或者软件运行的环境 目前比较流行的是Windows XP Linux Solaris和MacOS Java的平台不太一样 它由两个部分组成 即JVM和应用程序设计接口

.JVM

JVM是Java平台的核心 为了让编译产生的字节码能更好地解释与执行 因此把JVM分成了 个部分 JVM解释器 指令系统 寄存器 栈 存储区和碎片回收区

◆JVM解释器 即这个虚拟机处理字段码的CPU

◆JVM指令系统 该系统与计算机很相似 一条指令由 *** 作码和 *** 作数两部分组成 *** 作码为 位二进制数 主要是为了说明一条指令的功能 *** 作数可以根据需要而定 JVM有多达 种不同的 *** 作指令

◆寄存器 JVM有自己的虚拟寄存器 这样就可以快速地与JVM的解释器进行数据交换 为了功能的需要 JVM设置了 个常用的 位寄存器 pc(程序计数器) optop( *** 作数栈顶指针) frame(当前执行环境指针)和vars(指向当前执行环境中第一个局部变量的指针)

◆JVM栈 指令执行时数据和信息存储的场所和控制中心 它提供给JVM解释器运算所需要的信息

◆存储区 JVM存储区用于存储编译过后的字节码等信息

◆碎片回收区 JVM碎片回收是指将使用过的Java类的具体实例从内存进行回收 这就使得开发人员免去了自己编程控制内存的麻烦和危险 随着JVM的不断升级 其碎片回收的技术和算法也更加合理 JVM 版后产生了一种叫分代收集技术 简单来说就是利用对象在程序中生存的时间划分成代 以此为标准进行碎片回收

.Java应用程序设计接口

Java Application Programming Interface简称Java API 其中文名为Java应用程序设计接口 它是一个软件集合 其中有许多开发时所需要的控件 可以用它来辅助开发

lishixinzhi/Article/program/Java/hx/201311/26733


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/11044861.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-13
下一篇2023-05-13

发表评论

登录后才能评论

评论列表(0条)

    保存