美文网首页Android技术进阶Android开发经验谈Android开发
内存管理学习:java & C 内存管理区别

内存管理学习:java & C 内存管理区别

作者: 谁动了我的代码 | 来源:发表于2023-02-12 21:05 被阅读0次

    CLR vs JVM

    下面的流程图,基本描述了C#和Java总体的一个从源代码到最终的可执行的过程。

    源代码通过各自的编译器,编译成中间件的编码,这些中间件的编码可以被各自的运行时认识并管理,运行时载入中间件编码,转换成机器二进制运行在操作系统上。

    image

    运行时的内存区域

    要明白内存管理,首先必须知道运行时各种内存分配情况。

    其实总体来说,CLR和JVM中的内存分类基本一致,只是各自的逻辑划分和称谓有些差异。

    比较大的两块分别是堆和栈。

    • 栈都是线程私有的,每个方法在执行时都会创建一个栈帧用于存储局部变量、操作数栈、方法出口等等信息。栈的生命周期与线程相同,而栈中存放的内存,在各自属于的方法执行完成后,就会自动释放。
    • 堆是所有线程共享的。几乎所有的引用对象实例都是存放在这个区域的。而CLR或者JVM中下了大力气来管理的就是堆这块的内存区域,这种管理机制一般被称之为垃圾回收。
    • 一般来说,还有方法区(用于存储已经被加载的类信息,即时编译后的代码等数据,CLR中一般称做Type Object 区,JVM中叫Method Area),运行时常量池(存放各种编译时生成的字面量符号引用等信息),这些都可以认为是堆中的逻辑分块。

    垃圾回收机制

    垃圾回收机制就是用来管理堆中的内存了,当堆中的某个对象不再被使用到的时候,可以自动的将这块内存回收,置成可用状态。

    可达性分析

    那么如何知道某个对象不再被用到了呢,这个一般都是基于可达性分析后生成可达对象图来实现的;可达性分析就是通过从一些根对象出发,去遍历每一个被引用到的对象,当一个对象到根对象没有任何引用路径的时候,就认为该对象可以被回收。

    根对象一般包括:栈中定义的局部变量,全局的静态对象等等。

    而这里说的引用关系,其实是指强引用。而和强引用相对的,还有弱引用。

    强弱引用

    弱引用的引入其实是和垃圾回收器紧密相关的,因为垃圾回收的促发点是难以掌控的,而有一些对象的创建确实需要很大开销的,并且这些对象也不需要非常频繁的访问和很长的生命周期;那么作为平衡,就有了这个弱引用机制。弱引用即表示引用的对象可以被垃圾回收正常回收,但是如果在垃圾回收回收它之前想用它,还可以通过弱引用重新拿回来这个对象进行使用。

    CLR中只有强引用/弱引用之分。

    而JVM中除了这两个之外,额外还有软引用和虚引用两种:

    软引用是用来描述一些还有用但是非必须的对象,被软引用关联着的对象,只有在发生outofmemory的情况下才会被回收。

    而虚引用不对对象的生命周期和可达性分析产生任何影响,它唯一的作用是提供一种机制,可以在该对象被回收的时候收到一个系统通知。

    回收算法

    上面提到,通过可达性分析可以标记出所有需要回收的对象。那么如何回收呢?

    最简单的当然就是清除掉需要回收的对象的内存空间即可,这种方法实现简单,而且因为不改变存活的对象的地址,可以大大减少GC时的延时。但是带来的问题也很严重,它会让内存碎片化,最后导致虽然还有很多可用的内存,但是因为没有连续的可用的大内存而outofmemory。

    另外一种方法,就是需要对内存进行压缩处理,这种方法可以大大提高内存的利用率,并且为后续的内存分配带来便利(之后从已用空间的后面追加分配即可)。

    对于内存的压缩处理,其实也可以分为两种处理手段,复制和整理。

    • 复制算法就是把还存活的对象复制到另外一块内存中,它不太适合垃圾回收时有大量存活对象的情况,因为在这种情况下会需要准备大量的可用内存空间供复制使用。但是对于很少有存活对象的情况下,此种算法非常高效。
    • 整理就是在清楚了可回收对象后,将存活对象的位置移动,使得他们的内存成为连续的一整块,这种算法在很少可回收对象的情况下使用比较广泛。

    分代

    我们上面提到了各种不同的回收算法,各自适用与不同的场景。而CLR和JVM中分别通过对对象存活周期的分组来适配这些场景,然后每种场景去适用最高效的回收算法,这种分组称为代。

    • CLR中有三个代,分别是第0代,第1代,和第2代。每次促发垃圾回收后仍然存活的对象自动上升到下一个代。
    • JVM中有两个代,分别时新生代和老年代,新生代中一般还有两个区域eden区域和Survior区域,对象首次分配时都在eden区域,每次垃圾回收时候,如果一个对象还存活,会被复制到Survior区域,并且年龄+1,年龄到一定程度后就会进入老年代,如果新生代中的Survior区域的内存在GC时不够用了,那么这些存活的对象会直接进入老年代。
    • 还有一个大对象堆一说,其实大对象堆在CLR中可以被认为也在第2代中,JVM中大对象在老年代中。

    一般来说新生代或者第0代,都是采取的标记-复制的算法,而第1,2代或者老年代采用标记-整理的方法比较常见,当然大对象一般采用标记-清除的方式。

    C 语言手动管理内存

    如果操作不当会导致内存泄露(memory leak)和内存溢出(out of memory)。

    • 内存泄漏是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。
    • 内存溢出指程序申请内存时,没有足够的内存供申请者使用。
    • 学过 C 语言的朋友应该知道,可以 malloc 函数申请分配内存,使用完内存后,要用 free 释放内存。
    • 也就是说 malloc 函数和 free 函数是成双成对的,如果只写了 malloc 函数,而没写 free 函数,就是操作内存不当,会导致内存泄露。

    JAVA 自动管理内存

    但在 JAVA 中就不一样了,JAVA 程序员把控制内存的权利交给了虚拟机,程序员不直接操作内存。在 JAVA 中使用对象需要分配内存,虚拟机会自动分配内存,当使用完该对象,虚拟机通过垃圾回收器自动回收垃圾对象释放内存。因为虚拟机自动操作内存,所以 JAVA 程序员有时候可能感受不到内存的存在。

    那么接下来我们来了解一下 JAVA 虚拟机是怎样分配内存和释放内存的。我们在 JAVA 中创建对象时,会使用 new 关键字。当虚拟机接收到字节码指令 new 时,在做完一系列前置操作后,自动为该对象分配内存。

    虚拟机分配内存的方式有两种,分别是指针碰撞和空闲列表。

    • 假设 JAVA 堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,
    • 那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”(Bump thePointer)。

    如果 JAVA 堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”(FreeList)。

    对JAVA程序员来说是不用主动释放内存的,虚拟机会自动释放内存,也就是我们常说的通过垃圾回收器回收垃圾释放内存。

    垃圾回收算法

    虚拟机先通过可达性分析算法进行分析(CMS 和 G1 使用的是并发的可达性算法,也就是三色标记算法),如果是垃圾则标记出来,然后通过不同的回收算法回收垃圾,释放内存资源。

    常见的垃圾回收算法有,标记-清除算法、标记-复制算法、标记-整理算法,后续我会详细讲解这些算法的思想。

    注:

    这些垃圾回收算法会应用到不同的垃圾回收器中,常见的垃圾回收器如下:

    有Serial、ParNew、Parallel Scavenge、Serial Old、CMS、Parallel Old和G1,后续我也会重点讲解这一块内容。

    如果说 C 语言操作内存就像开手动挡汽车一样,需要自己手动换挡。那么 JAVA 操作内就像开自动挡汽车一样,不用自己换挡了,汽车自动帮你搞定。

    image

    文章内容讲述了Java与C++的内存管理问题;更多有关性能优化中内存问题;或者更多Android的进阶 技术可以参考《Android核心技术手册》点击进入查看。

    Java与C++内存管理的区别:

    对于C、C++程序开发人员来说,在内存管理领域,他们既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任。

    对于JAVA程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄露和内存溢出问题。由虚拟机管理内存看起来很方便,但是,也正是因为Java程序员把内存控制的权利交给了Java虚拟机,一旦出现内存泄露和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会成为一项异常艰难的工作。

    相关文章

      网友评论

        本文标题:内存管理学习:java & C 内存管理区别

        本文链接:https://www.haomeiwen.com/subject/fsodkdtx.html