32 位的平台上,线性地址空间为固定的 4GB,并且由于采用了保护机制,Linux内核将这 4GB 分为两部分,线性地址较高的 1GB(0xC0000000 到 0xFFFFFFFF )为共享的内核空间;而较低的 3GB 为每个进程的用户空间。由于每个进程都不能直接访问内核空间,而是通过系统调用间接进入内核,因此所有的进程都共享内核空间。而每个进程都拥有各自的用户空间,各个进程之间不能互相访问彼此的用户空间。 一个进程的用户地址空间主要由两个数据结构来描述。一个是 mm_struct 结构,它对进程的整个用户空间进行描述,简称内存描述符;另一个是 vm_area_struct 结构,它对用户空间中各个区间( 代码区、数据区等 )进行描述。 进程用户空间的描述 内存描述符 每个进程只有一个 mm_struct 结构,在每个进程的 task_struct 结构中,有一个指向该结构的指针。 struct mm_struct { struct vm_area_struct *mmap; /* list of VMAs * 继续阅读 >>


杜肖孟 17/12/10 14:47:55
写在前面: 分页机制完成线性地址到物理地址的转换 80x86 规定分页机制是可选的。分段和分页没有什么必然联系,分段可以说是 Intel 的 CPU 一直保持着的一种机制,而分页只是保护模式下的一种内存管理策略。想开启分页机制,CPU必须工作在保护模式,而工作在保护模式可以不开启分页。 分页机制由控制寄存器 CR0 中的 PG 位启用,如PG=1则启用分页机制,把线性地址转换为物理地址;如果PG=0则直接把段机制产生的线性地址当作物理地址使用。 为什么要分页? 问题的本质是在目前只分段的情况, CPU 认为线性地址等于物理地址,而线性地址是由编译器编译出来的,它本身是连续的,所以物理地址也必须要连续才行,但我们可用的物理地址不连续。换句话说,如果线性地址连续,而物理地址可以不连续,不就解决了吗。所以要解除线性地址和物理地址一一对应的关系,然后将他们的关系重新建立,通过某种映射关系,可以将线性地址映射到任意物理地址。 页与页表 为了效率起见,将线性地址空间分成若干大小相等的片,称为页( Page )。相应的地,逻辑上把内存划分为与页大小相等的若 继续阅读 >>


杜肖孟 17/12/02 14:51:54
内存为什么要管理 在OS中,每个运行的进程都会占用内存,那么操作系统势必要做好两件事:内存分配和内存回收。这便是本次实验要做的模拟实验了。 内存分配策略 FF(首次适应算法) 这种策略旨在从最低地址的空闲分区开始找起,找到合适的便进行分配。内存空间按起始地址从大到小排序。 优点:查找速度快 缺点:低地址会留下较多的内存碎片,高地址则会存留大块空闲分区。 BF(最佳适应算法) 这种策略每次分配都将最小块的满足需求空闲分区拿去分配。内存空间按空闲区从小到大排序。 优点:保留大的空闲分区。 缺点:造成很多小的空闲分区。 WF(最差适应算法) 这种策略每次分配都将最大块的满足需求空闲分区拿去分配。内存空间按空闲区从大到小排序。 优点:不会留下许多小的内存碎片。往往可以装入多个大内存程序。 缺点:留下大空闲区的可能减少了。 内存管理实验内容 模拟操作系统,既然是模拟,那么自然比真正的内存分配简单很多。 程序中两个链表: 空闲内存区块表,包含该空闲区的起始地址以及大小。程序初始化链表仅一个节点,大小为默认大小。 一分配内存区块表, 继续阅读 >>


李余通 17/11/10 18:56:25
信号量 信号量是一个计数器,常用于处理进程或线程的同步问题,特别是对临界资源访问的同步。 信号量的值大于或等于0时表示可供并发进程使用的资源实体数;小于0时代表正在等待使用临界资源的进程数 1、信号集的创建或打开 int semget(key_t key, int sems, int sem_flags); key 是由ftok()的到的键值。 nsems指明要创建的信号集包含的信号个数,改参数后面还会提到。semflg为操作标志 IPC_CREATE:调用semget()时,会将本信号集中的key值和其他信号集中的key进行对比,如果存在相同的key,说明信号集已存在,此时返回该信号集的标识符,否则新建一个信号集并返回其标识符。 IPC_EXCL:该宏和IPC_CREATE一起使用,否则没有意义。当 semflg取PC_CREATE|IPC_EXCL时,表示如果发现信号集已经存在,则返回错误,错误码 为EEXIST。 2、信号量的操作 int semop(int semid, struct sembuf *sops, size 继续阅读 >>


李佳灏 17/11/07 16:59:19
在上一篇博客JVM–解析Java内存区域及数据的内存分配与线程安全之间的一些联系中也说到了,想要理解volatile关键字,我们需要掌握Java虚拟机运行时数据区的相关知识,但是这还不够,只有理解了Java的内存模型,我们才能开始讲述volatile,而Java虚拟机运行时数据区是掌握Java内存模型的基础,所以如果你还没有看上一篇博客,请点击上方链接~~~ 引言 既然本节讲述volatile关键字,那么就先抛个砖引个玉(以下代码在64位jdk1.8下进行测试,不同jdk版本运行结果有可能不一样): public class RunThread implements Runnable { private boolean isRunning = true; public boolean isRunning() { return isRunning; } public void setRunning(boolean isRunning) { this.isRunning = isRu 继续阅读 >>


董恒毅 17/08/16 09:39:38
注:初学Java虚拟机,参考书籍《深入理解Java虚拟机》   最近,在学习spring框架,看书看的是云里雾里的,感觉看不下去了…..于是,就决定和其它东西换着来看,所以,就有了下面这篇博客..^-^   今天看了《深入理解Java虚拟机》的Java内存区域,决定写篇博客总结下,这块基本全是文字概念,难免有些枯燥,就权当给自己做做笔记,方便记忆…   开始我们就先来看看Java的内存区域划分吧. 运行时数据区域   Java虚拟机在执行Java程序的过程中会把它所管理的内存区域划分为若干个不同的数据区域.   下来,我们仔细聊聊Java虚拟机所管理的内存包括哪些运行时数据区域吧..    贴一张Java虚拟机运行时数据区的图片如下:         在网上又找到了一张更清晰,更好理解的图呦.          下面,针对上图的各个数据区做下详细介绍 程序计数器  程序计数器(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。   继续阅读 >>


董孟愿 17/08/08 16:33:51
最近一直在看《Java多线程编程核心技术》的第二章,主要讲的是线程共享变量与线程私有变量以及如何写出线程安全的代码。看这部分一开始没太注意,只是记住了一条规则,“类中的成员变量,也叫实例变量,也叫全局变量,它是非线程安全,是所有线程共享的变量,定义在方法中的私有变量是线程安全的,是每个线程私有的”。很好理解不是吗,然后一帆风顺的看到了关于volatile这部分的知识,看过之后我陷入了凌乱。。。关于这部分我之后进行总结,而现在我觉得你如果真的想写出线程安全的代码,那么Java的内存分配以及布局就是我们需要掌握的基础。为此,我粗略的看了一下《深入理解Java虚拟机》这本书的第二章,并且查阅了一些资料,现在汇总整理如下。 注:学习这部分内容之前如果你对进程的内存映像或数据在内存中的分配有大概的了解,建议你先忘记它们,因为这是讲Java虚拟机运行时的数据区,和之前的知识并不相同,所以学习的时候不要拿自己以前所了解的知识进行比较与衡量。 Java虚拟机运行时的数据区 先来看一张图片: 在这里我们只需要关注线程共享区中的堆,以及线程独占区中的虚拟机栈, 继续阅读 >>


董恒毅 17/08/08 14:26:58
共享内存是最高效的IPC机制,因为它不涉及进程之间的任何数据传输。这种高效率带来的问题是,我们必须用其他辅助手段来同步进程对共享内存的访问,否则会产生竞态条件。因此,共享内存通常和其他进程间通信方式一起使用。 Linux下有三种共享内存的IPC技术:System V共享内存、共享文件映射(mmap)、POSIX共享内存。 我们在这里只介绍POSIX共享内存。 要使用POSIX共享内存对象需要完成下列任务。 使用shm_open()函数打开一个与指定的名字对应的对象。shm_open()函数与open()系统调用类似,它会创建一个新的共享对象或打开一个既有对象。作为函数结果,shm_open()会返回一个引用该对象的文件描述符。 将上一步中获得的文件描述符传入mmap()调用并在其flags参数中指定MAP_SHARED。这会将共享内存对象映射进进程的虚拟地址空间。与mmap()的其他用法一样,一旦映射了对象之后就能够关闭该文件描述符而不会影响到这个映射。 创建共享内存对象 shm_open()函数创建和打开一个新的共享内 继续阅读 >>


冯鑫 17/08/02 21:15:34
在做网络安全事件分析的时候,都会遇到内存寻址的知识,例如上次跟大家分享的《 空指针漏洞防护技术》,就涉及到非法访问内存地址的问题。如果这个坎儿迈不过去,你就会迷失在代码中,更无从分析了。今天绿盟科技的安全技术专家就讲讲这个内存寻址的原理,文章分为上下两篇《内存寻址原理》及《内存寻址方式》。 随着信息化发展和数据处理能力需求的提高,对计算机硬件产品的性能和容量也提出了新的挑战,要求计算机处理能力也要能随实际情况需求的变动而提升、改变。 当下,一台普通的电脑硬盘容量也要200多G,内存也有4G;如此大容量的硬盘和内存,在处理大量数据或是大型游戏面前还是显得力不从心,需要通过扩容来满足需求,比如将内存由4G提升到8G或是16G不等。扩容后对个人体验确实提升不少。对于内存容量的提升需要有相应的硬件基础支撑,需要有能消化掉这么多内存的寻址地址。比如说如果一8位单片机如果要装载16G的内存,那就是暴殄天物。 哪里有需求哪里就有市场 ;计算机从8位的51单片机,20位8086寻址,发展到32位 win2003,64位win10,都是由于信息化需 继续阅读 >>


李东林 17/07/21 11:33:07
内存分配 在堆上分配内存 所谓堆是一段长度可变的虚拟内存,始于进程的未初始化数据段末尾(BSS)。通常将堆的当前内存边界称为“program break”。 我们依然结合进程内存布局看来。 改变堆的大小其实就像命令内核改变进程的program break位置一样,最初,program break正好位于未初始化数据段末尾之后。在program break的位置抬升后,程序可以访问新分配区域内的任何内存地址,而此时物理内存页尚未分配。内核会在进程首次试图访问这些虚拟内存地址时自动分配新的物理内存页。 系统调用brk()会将program break设置为参数addr所指定的位置。由于内存以页为单位进行分配,addr实际为下一个页的边界处。 当试图将program break设置为一个低于其初初始值的位置时,也就是低于&end位置时,可能会导致无法预知的问题。比如说我们常见的分段内存访问错误(segmention fault) 调用sbrk()将program break在原有地址上增加incer参数的大小,调用成功返回 继续阅读 >>


王一妃 17/07/17 12:22:15