内存管理

操作系统――虚拟内存

匿名 (未验证) 提交于 2019-12-03 00:28:02
(尚未完整,预计2018-06-18完成) 虚拟内存: 用辅助存储器(一般指磁盘)作为内存的补充。虚拟内存允许进程执行时只将部分程序放入内存,因此程序可以比物理内存大。虚拟内存的大小**受计算机寻址机制和可用的辅助存储器容量大限制,而不受内存容量的限制。 特征:①运行进程时只把现在要执行的页/段装入内存,其余页/段放在外存,需要时再利用 请求调入 页/段功能和 置换 功能将其调入内存。 ②在逻辑上扩充内存容量 ③访问速度接近于内存,没位(bit)成本接近于外存。 虚拟地址 :即 逻辑地址 ,虚拟内存中某个字节的地址,仿佛该字节在内存中(其实可能位于磁盘,但这对用户是透明的)。 虚拟地址空间 :分配给某个进程(程序)的虚拟地址范围。 实地址 :即物理地址。物理内存中某个字节的地址。 驻留集 :进程运行时装入内存的部分。 内存管理单元MMU :集成在CPU中,或作为一个协处理器。 功能:分解逻辑地址;逻辑地址到物理地址的转换;查找更新快表TLB;进程切换时清空TLB;发出缺页中断或越界中断;设置和检查页表中各个特征位等。 !#当访问一个不再内存的逻辑地址时,产生 缺页中断/缺段中断 ;OS阻塞该进程;启动磁盘I/O;装入所需的页/段后,将阻塞进程设置为就绪态。 ?#就绪挂起态和阻塞挂起态进程的换入/换出内存和虚拟存储的换入/换出内存有什么区别? 答:挂起态进程的所有内存驻留页

Pyforms 模拟内存管理模型

匿名 (未验证) 提交于 2019-12-03 00:26:01
环境 Python 3.6.3 + Pyforms 3.0.0 模拟: 内存管理模型的设计与实现 对内存的可变分区申请采用链表法管理进行模拟实现。要求: 设计思想 约定内存页数为16(索引地址为0-15),进程用字典表示,键是进程的标识符,值是进程的起始地址和占用内存页数。 每当有新的进程申请,检测内存中是否有足够的剩余空间,若没有,则紧缩内存,再次检查,若还是没有空间则输出失败信息;若有,根据选择的算法进行内存空间分配 变量和方法 主要变量: self.lastAddress 记录上一次分配的内存地址,用于邻近适度算法。 self.processes 记录进程信息,包括进程的进程名、起始地址和大小。 主要方法: getEmptyBlocks 获取空闲区域的起始地址和大小,函数会遍历整个内存,记录连续出现的‘N’(表示该页空闲)的位置和长度。 tightening 紧缩内存空间,从内存索引为0开始重新赋予进程起始地址,并根据起始地址更新GUI。 apply 申请进程,从GUI获取进程的名字和大小,检查内存剩余空间是否满足进程需求,满足需求时根据不同算法调度内存空间。算法见下: 首次适度算法:从头遍历getEmptyBlocks返回的记录(数据类型为列表),找到第一个满足要求的索引,从该索引更新进程信息。 最优适度算法:从getEmptyBlocks返回的数据中减去进程需求

RecyclerView和ViewPager内存管理的区别

匿名 (未验证) 提交于 2019-12-03 00:22:01
之所以想到写本文,是因为看到鸿洋微博的RecyclerView实现抖音效果的文章。里面讲了ViewPager实现会OOM,RecyclerView不会。 第一个get的点,RecyclerView打造成ViewPager,这个就不用多说了,SnapHelper封装了这一切 第二个get的点,为什么RecyclerView不会OOM呢? 这需要掌握RecyclerView一些浅显的原理。RecyclerView除了界面上显示的item,还有上下各2个供4个的预加载item。所以他内存中有 当前界面可见item数量+4 个数的item。他会在滑动的时候,不断bind新的数据。 ViewPager则是需要给他View的集合,你如果有10000个item,那内存中就必须有10000个item。 曾经我懵懂的时候问过Android老师,怎么才能只使用3个item去实现ViewPager? 这个问题挺白痴的,因为很简单就能实现。但是没想到老师说的答案令我震惊了,你没必要这么搞,他会自动替你管理,你移动到哪里就会有对应的item的销毁和创建。我说,假如我要写一个电子书,他有10000页,我肯定不能让他有10000页在内存中的对吗。他说,现在手机硬件都很好了,你做的这点优化微不足道。。。 这里就不写后续剧情了。我们固然可以用少量的item去实现ViewPager

位图内存管理

匿名 (未验证) 提交于 2019-12-03 00:19:01
最近看代码看到位图内存管理,在网上搜了下相关的资料,然后热度第一的csdn的一篇帖子上面解释的很难理解,叙述的也存在一些问题,后来找到很久的其他帖子,终于明白了,所以mark一下。 还使用二进制来表示内存的使用状态,就是1是‘占用了’,0是‘未占用’。上面的4个数组就是用来表示整数0-255使用8位(一个字节)的内存占用情况的。 首先,选取一个0-255之间的数字,我幸运数字12,那就12吧,12用8位二进制表示就是 0000 1100,先来讲第一个数组firstHoleSize,第一个数组的作用就是表示整数0-255用8位二进制表示的时候【从右到左开始看未被占用位数】有几位(注意:就是遇到1就不数了,有的文章里面喜欢称呼为‘洞’),0000 1100从右到左在遇到1之前0的位数为两位,那firstHoleSize[12]就是2,看下数组里面是不是。类似,22 用二进制表示为 0001 0110,从右到左遇到1之前0的位数为1,所以firstHoleSize[22]就是1。另外,如果是奇数的话,二进制最后一位肯定就是1,那么所有奇数的firstHoleSize都是0。 第二个数组与第一数组不同是从左数到右,方法与从右到左一致,特殊的就是如果数的大小大于等于2^7=128的话,那最左一位就是1,那么lastHoleSize[n](n>127)都是0 第三个表示的连续的最多位0(最大洞

解Bug之路:记一次JVM堆外内存泄露Bug的查找

匿名 (未验证) 提交于 2019-12-03 00:19:01
行业前列 百家号 01-15 16:30 前言 JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理内存的使用做了定量的分析,从而实锤了Bug的源头。 由于物理内存定量分析部分用到了linux kernel虚拟内存管理的知识,读者如果有兴趣了解请看ulk3(《深入理解linux内核第三版》) 内存泄露Bug现场 一个线上稳定运行了三年的系统,从物理机迁移到docker环境后,运行了一段时间,突然被监控系统发出了某些实例不可用的报警。所幸有负载均衡,可以自动下掉节点,如下图所示: 登录到对应机器上后,发现由于内存占用太大,触发OOM,然后被linux系统本身给kill了。 应急措施 紧急在出问题的实例上再次启动应用,启动后,内存占用正常,一切Okay。 奇怪现象 当前设置的最大堆内存是1792M,如下所示: -Xmx1792m -Xms1792m -Xmn900m -XX:PermSize=256m -XX:MaxPermSize=256m -server -Xss512k 查看操作系统层面的监控,发现内存占用情况如下图所示: 上图蓝色的线表示总的内存使用量,发现一直涨到了4G后,超出了系统限制。 很明显,有堆外内存泄露了。 查找线索 gc日志 一般出现内存泄露,笔者立马想到的就是查看当时的gc日志。

秋招C++开发学习之路day11

匿名 (未验证) 提交于 2019-12-03 00:08:02
day14(map set、STL组成、迭代器、epoll、继承、右值引用、include<>""区别、malloc、内存管理) map和set都是根据键值排序的,所以键值不能被修改。set只有键值和元素合一,所以不允许修改元素。 STL的allocaotr,就是分配器。用于封装STL容器在内存管理上的底层细节。 为了精密分工,分配器把new和delete两个阶段操作区分开来。 为了提高内存管理效率,减少申请小内存造成的内存碎片问题,SGI STL采用了两级配置。分配空间大于128B时直接用malloc(),realloc(),free()进行内存空间的分配和释放。小于128B时,用内存池技术,通过空间链表来管理内存。 map存放数据的形式是红黑树,unodered_map底层结构是哈希表。 STL组成成分,容器、迭代器、仿函数、算法、分配器、配接器。 分配器给容器分配内存空间,算法通过迭代器获取容器中的内容,仿函数可以协助算法完成各种操作,配接器用来套接适配仿函数。 迭代器是通过一种方法顺序访问一个聚合对象中的各个元素,而不需要知道对象内部表示,特性是与对象耦合。 迭代器不是指针,是一种类模板,模拟了指针的功能,封装了指针,相当于一种智能指针,根据对象不同的数据结构实现不同的操作。 迭代器返回的是对象的引用。 epoll原理 STL的resize()是改变容器的大小,vector

C++内存管理

匿名 (未验证) 提交于 2019-12-02 23:57:01
1.C++的内存分布 int value = 1 ; static int staticvalue = 1 ; void Test ( ) { static int staval = 1 ; int val = 1 ; int num1 = { 1 , 2 , 3 , 4 } ; char char2 [ ] = "abcd" ; char * char3 = "abcd" ; int * ptr1 = ( int * ) malloc ( sizeof ( int ) * 4 ) ; int * ptr2 = ( int * ) calloc ( 4 , sizeof ( int ) ) ; int * ptr3 = ( int * ) realloc ( ptr2 , sizeof ( int ) * 4 ) ; free ( ptr1 ) ; free ( ptr3 ) ; } 选项: A.栈 B.堆 C.数据段 D.代码段 value 在哪里? C _____ staticvalue 在哪里? C ____ staval 在哪里? C _____ val 在哪里? A ______ num1 在哪里? A _____ char2在哪里? D ____ * char2在哪里? A _____ char3在哪里? D ____ *pChar3在哪里? A _____

内存管理

匿名 (未验证) 提交于 2019-12-02 23:57:01
为了让每个进程认为 独占 地使用内存,并且让每个进程看到的内存是 一致 的,操作系统对物理内存、磁盘进行了 抽象 ,抽象出 虚拟内存 。并且把虚拟内存、物理内存以相同固定大小的 ҳ 进行切分管理( 分页 ),虚拟内存中叫页,物理内存中的叫页帧。 每个进程虚拟地址空间是独立的。用户访问的是虚拟内存的地址,即虚拟地址。需要通过 CPU 芯片上的 内存管理单元 MMU 硬件根据页表 翻译 成物理地址,才能真正访问内存。 页表 :每个进程都有它的独立的页表(放在内存里),用来存对虚拟页、物理页的 映射 。页表可以有多级页表,以时间换取空间(实际上,多级页表的地址翻译,并不比单级页表慢很多)。 如果直接按一个个程序加载到内存,会出现内存 碎片 。 后来出现 分段 机制,按程序的各段来存储,从而减少碎片,但是还是有很多。 所以引出分页,把程序分成更小的页(一般大小为 4KB )来管理内存。分得更小,会增加负荷,但实际上利大于弊。 通过虚拟地址 访问 数据: MMU 先通过它里面的 TLB 缓存查询,如果没有,则去内存中的 页表 进行查询。成功翻译成物理地址后,访问 一级缓存 获取数据。如果没有则访问 二级缓存 (可能还有三级缓存)。还是没有就访问 内存 。 物理内存 不够 时: 将不用的页面换出到磁盘中的 swap 分区 里。 包含: 程序代码和静态变量(根据可执行文件进行初始化,并固定了大小

C++内存管理

匿名 (未验证) 提交于 2019-12-02 23:57:01
new operator 我们平时使用的new是new操作符(new operator),就像sizeof一样是语言内置的,不能改变它的含义,功能也是一样的 比如: string * ps = new string ( "Memory Management" ); 相当于 void * memory = operator new ( sizeof ( string )); // 得到未经处理的内存,为String对象 call string :: string ( "Memory Management" ) on * memory ; // 调构造函数将字符串放到内存 string * ps = static_cast < string *>( memory ); // 使ps指针指向新的对象 new操作符总是做两件事: 1.调用相应的operator new分配内存 2.调用相应的构造函数 如下代码: class T { public : T (){ cout << "构造函数。" << endl ; } ~ T (){ cout << "析构函数。" << endl ; } void * operator new ( size_t sz ){ T * t = ( T *) malloc ( sizeof ( T )); //operator new就是简单的分配内存即可

C语言的内存管理

匿名 (未验证) 提交于 2019-12-02 23:52:01
堆和栈的区别: 栈的特征 执行的速度相对较快; 空间较小; 生存期由系统决定; 作用域较小; 有名空间,可以通过变量名或者数据名访问; 堆的特征 执行的速度相对较慢; 空间较大; 生存期由“自己”决定,malloc申请,free释放; 作用域很大(整个程序都可以访问); 无名空间,只能通过指针使用; C语言空间的申请 malloc 功能: 分配 size 字节的未初始化内存。若分配成功,则返回指向分配内存块最低位(首位)字节的,为任何拥有基础对齐的对象类型对齐的指针。 头文件: #include<stdlib.h> 原型: void* malloc( size_t size ); 参数: size - 要分配的字节数 返回值: 成功时:返回指向新分配内存的指针。为避免内存泄漏,必须用 free() 或 realloc() 解分配返回的指针。 失败时:返回空指针。 说明: malloc申请的空间为连续空间;malloc申请的是没有初始化的空间; 返回值类型是void * 该类型表明malloc返回的地址空间中的数据类型是不确定,必须经过强制类型转换才可以使用。 realloc 功能: 先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间