内存碎片

JVM垃圾回收详解

有些话、适合烂在心里 提交于 2020-02-16 22:38:54
通常,我们在写java程序的时候,似乎很少关注内存分配和垃圾回收的问题。因为,这部分工作,JVM已经帮我们自动实现了。 这样看起来,好像很美好,但是任何事情都有两面性。虽然JVM会自动的进行垃圾回收,但是,如果遇到有些问题,JVM自己也处理不了呢? 因此,我们需要了解一下JVM垃圾回收是怎样运作的,这样才能在遇到问题的时候,有的放矢。所以,今天就来聊一聊JVM的垃圾回收吧。 首先,思考一下,为什么需要进行垃圾回收? 我们知道,在创建对象的时候,Java会把对象的内容放到堆中。随着时间的推移,堆中的对象肯定会越来越多,但是,堆的大小是有限制的。如果,我们不进行垃圾回收,也就是把无用的对象进行清除和回收,那么JVM将不堪重负,最终导致内存泄漏。 既然我们需要进行垃圾回收,那么,首先得知道什么是垃圾。 在垃圾收集器对堆内存进行回收前,会先判断哪些对象还在“存活”,哪些对象已经“死去”(即不可能再被任何途径使用的对象),这些“死去”的对象,就是我们需要进行回收的垃圾。 那么,通过什么方式去判定是否为垃圾呢?(即判定对象是否存活) 引用计数算法(已淘汰) 引用计数算法,是指给对象中添加一个引用计数器,每当有一个地方引用它时,计数器的值就加1,当引用失效时,计数器的值就减1。当计数器值为0时,该对象就会被回收。 可以说,引用计数算法的实现非常简单,判定效率也很高。但是,我们忽略了一个问题

垃圾收集算法

不想你离开。 提交于 2020-02-15 10:56:02
本文节选自《深入理解Java虚拟机:JVM高级特性与最佳实践》【作者:周志明】 由于垃圾收集算法的实现涉及大量的程序细节,而且各个平台的虚拟机操作内存的方法又各不相同,因此本节不打算过多地讨论算法的实现,只是介绍几种算法的思想及其发展过程。 3.3.1 标记-清除算法 最基础的收集算法是“标记-清除”(Mark-Sweep)算法,如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象,它的标记过程其实在前一节讲述对象标记判定时已经基本介绍过了。之所以说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其缺点进行改进而得到的。 它的主要缺点有两个:一个是效率问题,标记和清除过程的效率都不高;另外一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。 标记-清除算法的执行过程如图3-2所示。 图3-2 “标记-清除”算法示意图 3.3.2 复制算法 为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉

浅谈Windows虚拟内存

橙三吉。 提交于 2020-02-15 10:54:16
  本人电脑2G内存,写程序打开很多窗口电脑都能正常使用,就是一般看个2、3个小时的电影,电脑才会出现内存不足的情况,以前在学校也帮老师装过SqlServer2008,我老师的C盘不是盖的,可不是一般的小,他的是winXP系统,装sql时总报内存不足,我上网查了下资料,将其虚拟内存temp文件夹移到了D盘才勉强装上Sql,今天针对我的电脑Win7系统,从网上找了些资料,发现问题还挺大的,特地与大家分享....    1、何为虚拟内存?   内存在计算机中的作用很大,电脑中所有运行的程序都需要经过内存来执行,如果执行的程序很大或很多,就会导致内存消耗殆尽。为了解决这个问题,Windows运用了虚拟内存技术,即拿出一部分硬盘空间来充当内存使用,这部分空间即称为虚拟内存,虚拟内存在硬盘上的存在形式就是 PAGEFILE.SYS 这个页面文件。   虚拟内存只是真实内存不足的补充,所以不要加以神化,虚拟内存的读写性能(即硬盘的读写)只有真正内存性能的几十分之一,而且对硬盘损伤很大!能不用则不用,能少用则少用!原则是够用+留少量余量即可。    2、虚拟内存设置的误区   其一:虚拟内存越大越好?   答案:错。虚拟内存过大,既浪费了磁盘空间,又增加了磁头定位的时间,降低了系统执行效率,没有任何好处。正确设置可节省256MB-4G左右空间(视内存大小)   其二:虚拟内存不应该设在系统盘C盘

程序的内存分配

北城以北 提交于 2020-02-15 07:14:06
本人收集整理!感觉非常经典,,与众人阅之! 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack):由编译器自动分配释放 ,站的特点是空间小但被CPU访问的速度快,使用户存放程序中临时创建的变量.由于桟的后进后出的特点,所以桟特别方便用来保存和恢复调用现场.用于存储占用空间长度不变并且占用空间小的数据类型的内存段,而相同类型的数据占用的空间是等长的,其操作方式类似于数据结构中的栈。 2、堆区(heap):它大小并不固定,可动态扩张或缩减.用于存放数据长度可变或内存占用较大的数据, 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。 3、全局区(静态区static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 4、文字常量区:常量字符串就是放在这里的。 程序结束后由系统释放 5、程序代码区:代码区用来存放可执行文件的操作指令,(即二进制代码)也就是可执行程序内存中的镜像.代码段需要防止运行时被非法修改,所以只允许读取操作.如程序中的函数就存储在这段内存。 二、例子程序 这是一个前辈写的,非常详细 //main.cpp int a = 0; 全局初始化区 char

内存

半城伤御伤魂 提交于 2020-02-15 07:10:01
代码区:存放程序的代码,即CPU执行的机器指令,并且是只读的。 常量区:存放常量(程序在运行的期间不能够被改变的量,例如: 10, 字符串常量 ”abcde”, 数组 的名字等) 静态区(全局区): 静态变量和全局变量 的存储区域是一起的,一旦静态区的内存被分配, 静态区的内存直到程序全部结束之后才会被释放。 堆区:由程序员调用malloc()函数来主动申请的,需使用free()函数来释放内存,若申请了堆区内存,之后忘记释放内存,很容易造成内存泄漏。 栈区:存放函数内的 局部变量 , 形参 和 函数返回值 。栈区之中的数据的作用范围过了之后,系统就会 回收 自动管理栈区的内存(分配内存 , 回收内存), 不需要开发人员来手动管理 。栈区就像是一家客栈,里面有很多房间,客人来了之后自动分配房间,房间里的客人可以变动,是一种动态的数据变动。 1、堆和栈的区别 (1)存储内容 栈:函数的各个参数、局部变量、返回值等等。 堆:头部用一个字节存放堆的大小,具体内容有程序员来安排。 (2)申请方式不同 栈是由系统自动分配释放,而堆是由程序员自己分配释放。 (3)申请大小限制 栈:是一块连续的内存区域,大小是固定的。如果申请的空间超过栈的剩余空间,会提示overflow。 堆:不连续。因为系统使用的是链表来存储空闲内存地址的,所以不连续。比较灵活。 操作系统有一个记录空闲内存地址的链表

「Nosql」Redis小记-内存解析&内存消耗篇

痴心易碎 提交于 2020-02-15 05:40:42
🍄 博客搬家:初版发布于 2017/08/12 18:32 🌺 原博客地址: https://my.oschina.net/sunqinwen/blog/1507171 前置:redis内存指标 注:本文默认读者已初步学会使用redis了。 首先我们通过info命令查看相关指标,其中几个memory的重要指标整理出来如下: 属性 解释 used_memory redis内部存储的所有数据的内存总占用量(自身内存+对象内存+缓冲内存) used_memory_ress redis进程占用的总物理内存 mem_fragmentation_ratio used_memory_ress与used_memory的比值,即为内存碎片率 mem_allocator 内存分配器,默认为jemalloc 一、碎片率 ① 当 内存碎片率>1 时,说明redis进程占用物理内存的总量大于Redis实际存储数据(表1-1第一行)的内存占用量,溢出来的部分内存被内存碎片消耗,如果溢出部分过大,则说明内存碎片率严重。 ② 相反的,如果 碎片率<1 时,则说明Redis存储的数据总量已经超出了redis进程占用内存的总量,造成这种情况是因为操作系统把Redis内存交换至硬盘导致(swap),由于硬盘读取速度远远慢与内存,因此这种情况下redis性能极差,可能出现僵死。 二、redis内存消耗的几个来源 2.1:

redis内存消耗详解

[亡魂溺海] 提交于 2020-02-14 22:43:06
Redis所有的数据都存在内存中,相对于廉价的硬盘,内存资源还是比较昂贵的,因此如何高效利用redis内存变得非常重要。 内存消耗分析 管理内存的原理和方法 内存优化技巧 一、内存消耗 理解redis内存,首先要掌握redis内存消耗在哪些方面。有些内存消耗是必不可少的,而有些可以通过参数调整和合理使用来规避内存浪费。 1.1 内存使用统计 首先需要了解redis自身使用内存的统计数据,可通过执行info memory命令来获取内存相关指标 used_memory redis分配器分配的内存总量,也就是内部存储的所有数据内存占用量 used_memory_human 以可读的格式返回used_memory used_memory_rss 从操作系统的角度显示redis进程占用的物理内存总量 used_memory_peak 内存使用的最大值,表示used_memory的峰值 used_memory_peak_human 以可读的格式返回used_memory_peak used_memory_lua Lua引擎所消耗的内存大小 mem_fragmentation_ratio used_memory_rss/used_memory比值。表示内存碎片率 mem_allocator redis 所使用的内存分配器,默认为jemalloc 需要重点关注的指标有:used_memory

java与C++的区别

不问归期 提交于 2020-02-14 17:46:42
“作为一名C++程序员,我们早已掌握了面向对象程序设计的基本概念,而且Java的语法无疑是非常熟悉的。事实上,Java本来就是从C++衍生出来的。”   然而,C++和Java之间仍存在一些显著的差异。可以这样说,这些差异代表着技术的极大进步。一旦我们弄清楚了这些差异,就会理解为什么说Java是一种优秀的程序设计语言。本附录将引导大家认识用于区分Java和C++的一些重要特征。   (1) 最大的障碍在于速度:解释过的Java要比C的执行速度慢上约20倍。无论什么都不能阻止Java语言进行编译。写作本书的时候,刚刚出现了一些准实时编译器,它们能显著加快速度。当然,我们完全有理由认为会出现适用于更多流行平台的纯固有编译器,但假若没有那些编译器,由于速度的限制,必须有些问题是Java不能解决的。   (2) 和C++一样,Java也提供了两种类型的注释。   (3) 所有东西都必须置入一个类。不存在全局函数或者全局数据。如果想获得与全局函数等价的功能,可考虑将static方法和static数据置入一个类里。注意没有象结构、枚举或者联合这一类的东西,一切只有“类”(Class)!   (4) 所有方法都是在类的主体定义的。所以用C++的眼光看,似乎所有函数都已嵌入,但实情并非如何(嵌入的问题在后面讲述)。   (5) 在Java中,类定义采取几乎和C++一样的形式。但没有标志结束的分号

内存管理:如何避免内存溢出和频繁的垃圾回收?

老子叫甜甜 提交于 2020-02-14 01:41:54
自动内存管理机制的实现原理 做内存管理,主要需要考虑 申请内存和内存回收 这两个部分。 申请内存的逻辑非常简单: 1、计算要创建对象所需要占用的内存大小; 2、在内存中找一块儿连续并且是空闲的内存空间,标记为已占用; 3、把申请的内存地址绑定到对象的引用上,这时候对象就可以使用了。 内存回收 内存回收需要做这样两件事儿: 1、先是要找出所有可以回收的对象,将对应的内存标记为空闲 2、整理内存碎片。 采用GC算法找出可回收对象,此类算法大多采用 “标记-清除“ 算法或其变种,此类算法分为标记和清除两阶段: 标记阶段:从 GC Root 开始,你可以简单地把GC Root 理解为程序入口的那个对象,记所有可达的对象,因为程序中所有在用的对象一定都会被这个 GC Root 对象直接或者间接引用。 清除阶段:遍历所有对象,找出所有没有标记的对象。这些没有标记的对象都是可以被回收的,清除这些对象,释放对应的内存即可。 缺点: 效率不高、空间问题、在执行标记和清除过程中,必须把进程暂停(Stop the world)。 java虚拟机中常见的垃圾收集器及其对应垃圾收集算法: 垃圾收集器 1、 Serial收集器。 (虚拟机运行在Client模式下的默认新生代收集器) 单线程收集器,在进行垃圾收集时,必须暂停所有其他的工作线程,直至结束。 2、 ParNew收集器 Serial收集器的多线程版本

内存池的设计和实现总结(一)

回眸只為那壹抹淺笑 提交于 2020-02-13 08:19:36
  C/C++下内存管理是让几乎每一个程序员头疼的问题,分配足够的内存、追踪内存的分配、在不需要的时候释放内存——这个任务相当复杂。而直接使用系统调用malloc/free、new/delete进行内存分配和释放,有以下弊端: 调用malloc/new,系统需要根据“最先匹配”、“最优匹配”或其他算法在内存空闲块表中查找一块空闲内存,调用free/delete,系统可能需要合并空闲内存块,这些会产生额外开销 频繁使用时会产生大量内存碎片,从而降低程序运行效率 容易造成内存泄漏   内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。   本章先实现一个简单的内存池(CSingleMemoryPools)。该内存池提供一定数量、大小相等的内存块。该实例中,CSingleMemoryPools中的m_pMemoryFreeList负责对空闲内存块进行管理,每个内存块以_MemoryBlock类进行管理,其中首部有4个字节的指针块地址 + 4个字节的list表首地址 + 4位验证码,然后才是分配的内存。 1 #pragma once 2 3 //开发一个简单的内存池,用于内存管理。 4 5 #include