内存碎片

堆和栈的区别(转过无数次的文章)

我怕爱的太早我们不能终老 提交于 2020-03-13 11:37:31
一、预备知识—程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其 操作方式类似于数据结构中的栈。 2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回 收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。 3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的 全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另 一块区域。 - 程序结束后由系统释放。 4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放 5、程序代码区—存放函数体的二进制代码。 二、例子程序 这是一个前辈写的,非常详细 //main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main() { int b; 栈 char s[] = "abc"; 栈 char *p2; 栈 char *p3 = "123456"; 123456\0在常量区,p3在栈上。 static int c =0; 全局(静态)初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); 分配得来得10和20字节的区域就在堆区。

C# 指针使用总结

拈花ヽ惹草 提交于 2020-03-13 09:37:32
C#为了类型安全,默认并不支持指针。但是也并不是说C#不支持指针,我们可以使用unsafe关键词,开启不安全代码(unsafe code)开发模式。在不安全模式下,我们可以直接操作内存,这样就可以使用指针了。在不安全模式下,CLR并不检测unsafe代码的安全,而是直接执行代码。unsafe代码的安全需要开发人员自行检测。 一、Vs2010中开启unsafe code 的方式 在方法、类、代码块中使用unsafe关键词,如: 1 unsafe static void Main(string[] args){ //代码} 2 3 unsafe 4 { 5 //代码块 6 } 然后再项目上点击鼠标右键,选择“属性”,在“生成”选项卡中选中“允许不安全代码” 二、C#可以定义为指针的类型有 sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, struct(结构体),结构体中只能包括非托管类型。 三、C#指针操作符 操作符 说明 * 取值运算符 & 取址运算符 -> 通过指针处理结构体中的数据(获取或赋值) ++与– 指针增、减操作 fixed 用户暂时固定托管代码中引用类型的位置。 Stackallc 分配内存 例如分配内存 1 char* cptr =

JavaScript GC简书

风流意气都作罢 提交于 2020-03-11 18:47:10
1.垃圾回收算法 垃圾:无法再被访问的对象或内存空间 延迟:指平均每次垃圾回收开始到结束需要的时间。 吞吐量:指平均一定时间内能回收多少内存,内存多少这个概念非常广泛,可以指多少个对象,也可以指多少字节的空间,具体的应该看指标应需求而异。 根节点:如全局变量上的对对象的引用、栈上对对象的引用等用户一定能够访问到的地址,是寻找活对象的入口。 下面简单地介绍引用计数、Mark-Sweep、Mark-Copy、Mark-Compact四种垃圾回收算法 1.1 引用计数 这是最初级的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。我们可以为每个对象都增加一个计数器,来记录对这个对象的引用数量,当引用计数归零时,这个对象变成了垃圾 引用计数的优点如下: (1)内存释放及时,当一个对象死亡时其占用的内存马上被释放 (2)延迟低,内存释放的时间均匀地分布在各个时间段 缺点如下: (1)每个对象需要附带一个计数字段的空间 (2)引用复制和销毁时需要对改变计数字段,这可能涉及到相对昂贵的原子操作 (3)无法处理循环引用,比如两个对象互相引用对方的情况 进阶话题:当一个大对象的引用归零时,常常会导致一大批的对象引用归零,这种成批释放的情况非常常见

记录一下jvm的相关知识点

有些话、适合烂在心里 提交于 2020-03-11 13:22:06
java 运行时数据区域: 程序计数器 => (每个线程都包含一个程序计数器)用来记录字节码执行的行号,字节码指令的循环,跳转,异常处理,线程恢复等需要依靠计数器。 Java虚拟机栈 => 主要用来描述Java方法执行的内存模型,(每个线程都包含一个虚拟机栈)主要用来处理方法的调用,虚拟机栈中的存储单元是栈帧,方法在执行的同时都会在虚拟机栈中创建一个栈帧,栈帧包含操作数栈,局部变量表,动态链接和方法出口等,每个方法从调用到执行完毕都对应着一个栈帧在虚拟机栈中的入栈和出栈的过程。局部变量表的存储单位为slot(4个字节),因此double 和long类型需要占用2个slot的存储空间。 栈的深度有一定限制,当深度操作最大的调用栈大小会出现StackOverflowError异常。 本地方法栈 => 为虚拟机执行java方法的服务(native方法),类似虚拟机栈 java堆 => 对象和数组存储的场所,也是gc收集器的主要管理区域,现在收集器基本采用分代收集算法,可通过-Xmx -Xms来分配堆内存大小,当堆内存无法分配内存时,会出现OutOfMemoryError异常。 方法区 => 用于存储已被虚拟机加载的类信息,静态变量,常量以及即时编译器编译后的代码等,方法区无法分配内存是会出现OutOfMemoryError异常。 运行时常量池 =>方法区的一部分

jemalloc和内存管里

亡梦爱人 提交于 2020-03-11 12:25:24
netty的buffer引入了缓冲池。该缓冲池实现使用了jemalloc的思想。为了看懂这块代码学写了内容分配的知识。这里讲的内存分配是堆的内存分配,其他内容本文不会涉及。 内存分配是面向虚拟内存的而言的,以页为单位进行管理的,页的大小一般为4kb,当在堆里创建一个对象时(小于4kb),会分配一个页,当再次创建一个对象时会判断该页剩余大小是否够,够的话使用该页剩余的内存,减少系统调用。真实的内存分配算法比这个复杂了,效率不好的内存算法会导致出现很多内存碎片。 内存分配的核心思想概括起来有3条 1:首先讲内存区(memory pool)以最小单位(chunk)定义出来 ,然后区分对象大小分别管理内存,小内存定义不同的规格(bins),根据不同的bin分配固定大小的内存块,并用一个表 管理起来,大对象则以页为单位进行管理,配合小对象所在的页,降低碎片,设计一个好的存储方案(metadata)减少对内存的占用,同时优化内存信息的存储。以使对每个bin或大内存区域的访问性能最优且有上限。 2:当释放内存时,要能够合并小内存为大内存,该保留的保留下次可快速响应,不该保留的释放给系统 3:多线程环境下,每个线程可以独立的占有一段内存区间(TLS),这样线程内操作可以不加锁 jemalloc是freebsd的内存分配算法,他的layout如下: 1:arena:把内存分成许多不同的小块来分而治之

ptmalloc2

拟墨画扇 提交于 2020-03-11 08:04:20
本文参考华庭(庄明强)的ptmalloc2 源码剖析 简介: ptmalloc实现了malloc(),free()以及一组其他函数,以提供动态内存管理,同时支持多线程。分配器处于用户空间和内核空间之间,响应用户的分配请求,向操作系统申请内存。总体思想是先“批发”一块大内存,而后“零售”给用户,同时也实现了高效的回收机制。 Main_area / non_main_area(主分配区和非主分配区): 在linux之前版本使用的内存分配机制只有一个主分配区,然而多线程下访问要加锁,所以在ptmalloc中区分出了主分区和非主分区。主分区只有一个,而非主分区可以有多个,分区一旦增加就不会减少。 主分区可以访问heap和memory mapping segment(可调用brk()/sbrk()/mmap()),而非主分区只能访问memory mapping segment(只可以调用mmap())。 chunk组织 ptmalloc通过chunk来管理内存,给User data前存储了一些信息,使用边界标记区分各个chunk。 这个是一个使用中的chunk,返回给用户的指针是上图的mem,在mem上方分别存放了前一个chunk的大小和本chunk的大小,chunk对齐(alignment = 2 ^n; n>=3),对于默认8字节对齐后10个bit为一定为0

Redis & Redis 桌面管理工具Redis Desktop Manager

你。 提交于 2020-03-11 07:41:49
Redis简述 Redis 是完全开源免费的,遵守BSD协议,先进的key - value持久化产品。它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。 redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类keyvalue存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Python,Ruby,Erlang,PHP客户端,使用很方便。问题是这个项目还很新,可能还不足够稳定,而且没有在实际的一些大型系统应用的实例。此外,缺乏mc中批量get也是比较大的问题,始终批量获取跟多次获取的网络开销是不一样的。 性能测试结果: SET操作每秒钟 110000 次,GET操作每秒钟 81000 次,服务器配置如下: Linux 2.6, Xeon X3320 2.5Ghz. stackoverflow 网站使用 Redis 做为缓存服务器。 安装过程: Redis是一种高级key-value数据库。它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富。有字符串,链表,集 合和有序集合。支持在服务器端计算集合的并,交和补集(difference)等,还支持多种排序功能

Redis内存使用优化与存储

眉间皱痕 提交于 2020-03-11 06:42:22
常用内存优化手段与参数   我们知道Redis实际上的内存管理成本非常高,即占用了过多的内存,所以我们讨论通过一系列的参数和手段来控制和节省内存。   首先最重要的一点是不要开启Redis的VM选项,即虚拟内存功能,这个本来是作为Redis存储超出物理内存数据的一种数据在内存与磁盘换入换出的一个持久化策略,但是其内存管理成本也非常的高,并且我们后续会分析此种持久化策略并不成熟,所以要关闭VM功能,请检查你的redis.conf文件中 vm-enabled 为 no。   其次最好设置下redis.conf中的maxmemory选项,该选项是告诉Redis当使用了多少物理内存后就开始拒绝后续的写入请求,该参数能很好的保护好你的Redis不会因为使用了过多的物理内存而导致swap,最终严重影响性能甚至崩溃。   另外Redis为不同数据类型分别提供了一组参数来控制内存使用,我们在前面详细分析过Redis Hash是value内部为一个HashMap,如果该Map的成员数比较少,则会采用类似一维线性的紧凑格式来存储该Map, 即省去了大量指针的内存开销,这个参数控制对应在redis.conf配置文件中下面2项: hash-max-zipmap-entries 64 hash-max-zipmap-value 512 hash-max-zipmap-entries  

Node.js的C++扩展教程(二)

梦想的初衷 提交于 2020-03-11 00:59:51
今天我们讲一下关于V8中的内存机制、隔离实例、上下文、脚本。 内存机制 1.基本概念 在Chrome V8中,内存机制是非常重要的,其中就包含它内在的各种概念。V8高效的一个重要原因就是它的内存机制。 Chrome V8中JavaScript的数据类型(Number、Object、Function等)都是由V8内部的内存机制进行管理的。也就是说如果你在自己的JavaScript代码中声明了一个变量/函数/对象,那么这个变量/函数/对象将被V8的内存机制进行管理。 Chrome V8所创建的C++类型能被你编写的C++代码(如C++扩展)所访问,并且其跟JavaScript中操作的是在内存中相同的存储单元。比如说你在JavaScript中声明了let a = 1;,那么在C++扩展中是可以被访问到的。 举个例子,在JavaScript中定义了一个字符串: let a = "hello world" Chrome V8会对应的创建一个v8::String类型的对象,里面有一堆Chrome V8内置的数据信息。 这些数据类型中都有对数据元信息的一个引用,用于内存管理。 2.堆内存类型 堆内存类型有以下几种: 新生代内存区:基本的数据对象(小数据对象)都被分配到这里,其特点是小而频,也就是空间小,垃圾回收频繁。 老生代指针区:这是一堆指向老生代内存区具体数据内容的指针。 老生代数据区

C与C艹的内存管理方式

自古美人都是妖i 提交于 2020-03-10 08:57:12
  C 内存开辟出的空间一般可以分成: 代码段,数据段( 初始化的数据段, 为初始化的数据段BSS ),堆,栈   代码段 :保存程序文本,指令指针EIP就是指向代码段,可读可执行不可写   数据段 :保存初始化的全局变量和静态变量,可读可写不可执行   BSS :未初始化的全局变量和静态变量   堆(Heap) :动态分配内存,向地址增大的方向增长,可读可写可执行     栈(Stack) :存放局部变量,函数参数,当前状态,函数调用信息等, 向地址减小的方向增长 ,非常非常重要,可读可写可执行      最特别的是 栈stack ,它和别人是反着的!在Windows平台上,栈都是从上(高)向下(低)生长的!。   关于函数调用举个例子: int i= 0x22222222; char szTest [] = "aaaa";//a的ASCII码为0x61 func(i, szTest);   当访问进入func函数时,栈中的形式为(左侧地址 右侧数据):   0x0013FCF0 0x0013FCF8   0x0013FCF4 0x22222222   0x0013FCF8 0x61616161 PS: c++中语句解析顺序和函数调用时候顺序一致:由右向左! 比如如下语句,在输入vector为空时会造成 访问越界! void numIslands(vector<vector