在前面的几章中,我们涉及到了资源限制的主题。在这一章,我们将会讨论管理我们资源分配的方法,然后讨论多个用户连续处理文件的方法,最后我们来讨论Linux系统所提供的工具如何处理将普通文件的限制用作一个数据存储介质的问题。
我们可以数据管理总结为如下三个方面:
动态内存管理:要做些什么而Linux不允许我们做什么
文件锁:协作锁,共享文件锁区域,以及避免死锁
dbm数据:一个基本的,大多数Linux系统中所提供的非基于SQL数据库的函数库
管理内存在所有的计算机系统中内存是稀有资源。不论有多少内存可用,看起来都会显得不足。再也不是以前那种情况了:可以寻址1M内存被认为对于所有人来说都是足够的,然而现在512M的内存已成了最低配置了。
由操作系统的最早版本开始,Unix风格的操作系统就具有一个非常清晰的方法来管理内存,Linux也是如此,因为他实现了X/Open规范。Linux程序,除了一些特殊的嵌入式程序除外,绝不允许直接访问物理内存。程序所看到的只是一个被小心管理的场景。
Linux使用一个清晰的直接寻址的内存空间来提供程序。另外,他提供了保护,所以不同的程序之间彼此会被保护,而且在机器内部允许程序透明的访问比实际的物理内存大得多的内存空间,只要机器很好的进行了配置而且有足够的交换空间。
简单的内存分配我们在标准的C库中使用malloc调用来分配内存。
#include <stdlib.h>
void *malloc(size_t size);
注意,Linux(遵循X/Open规范)不同于某些Unix实现,因为他并不需要一个特定的malloc.h包含文件。另外要注意就是,指定要分配的字节数的size参数并不是int,尽管他通常是一个无符号整形。
在绝大多数的Linux系统上,我们可以分配大量的内存。让我们由一个非常简单的程序开始,但是这并不适用于老的基于MS-DOS的程序,因为他们并不允许访问超出PC的640K的内存。
试验--简单的内存分配输入下面的程序,memory1.c:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define A_MEGABYTE (1024 * 1024)
int main()
{
char *some_memory;
int megabyte = A_MEGABYTE;
int exit_code = EXIT_FAILURE;
some_memory = (char *)malloc(megabyte);
if (some_memory != NULL) {
sprintf(some_memory, “Hello World\n”);
printf(“%s”, some_memory);
exit_code = EXIT_SUCCESS;
}
exit(exit_code);
}
当我们运行这个程序时,其输出结果如下:
$ ./memory1
Hello World
工作原理这个程序要求malloc库为其指定一个到1M内存的指针。我们要进行检测以确保malloc函数调用成功,然后使用其中的一部分内存来演示其存在。当我们运行这个程序时,我们应可以看到打印出Hello World字符串,从而表示malloc确实返回了可用的兆字节空间。我们并没有检测所分配的全部字节空间,我们需要信任malloc代码!
注意,因为malloc返回一个void *指针,我们将其转换成我们所需要的char *类型。malloc函数确保返回对齐的内存空间,从而可以将其转换为任何类型的指针。
简单的原因在于绝大多数的Linux系统使用32位整数以及使用32位指针来指向内存,这允许我们最多可以指定4GB的内存空间。使用32位指针,而不需要段寄存器或是其他技巧来直接寻址的技术就被称之为普通32位内存模式。这种模式也用于Windows XP以及Windows 9x/Me的32程序。我们不应依赖于整数是32位的,因为也存在正在使用的Linux的64位版本。
分配大内存现在我们已经看到Linux已经超出了MS-DOS内存模式的限制,下面我们会提出一个更为困难的问题。在下面的程序中,我们会要求分配大于机器中实际物理内存大小的内存空间,所以我们会期望malloc函数会由于实际的内存数量而失败,因为内核以及其他运行的进程都会占用一定的内存。
试验--要求所有的物理内存
在memory2.c中,我们会要求分配大于机器实际内存数量的内存。也许我们需要依据我们实际的物理内存数量来调整PHY_MEM_MEGS值。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define A_MEGABYTE (1024 * 1024)
#define PHY_MEM_MEGS 256 /* Adjust this number as required */
int main()
{
char *some_memory;
size_t size_to_allocate = A_MEGABYTE;
int megs_obtained = 0;
while (megs_obtained < (PHY_MEM_MEGS * 2)) {
some_memory = (char *)malloc(size_to_allocate);
if (some_memory != NULL) {
megs_obtained++;
sprintf(some_memory, “Hello World”);
printf(“%s - now allocated %d Megabytes\n”, some_memory,
megs_obtained);
}
else {
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
程序会产生类似于下面的输出:
$ ./memory2
Hello World - now allocated 1 Megabytes
Hello World - now allocated 2 Megabytes
...
Hello World - now allocated 511 Megabytes
Hello World - now allocated 512 Megabytes
工作原理这个程序非常类似于前面的例子。他只是进行简单的循环,要求分配越来越多的内存。令人惊奇的是他仍然可以正常工作,因为我们创建了一个会使用所有物理的程序。注意,在这里我们对于malloc调用使用了size_t类型。
另一个有趣的特点在于,至少在我们试验的这个机器上是这样,运行这个程序时屏幕会闪动。所以我们不仅是使用了全部的内存,而且我们可以很快的完成这些所要求的工作。
下面我们来探讨这个特性,并且我们会看一下在memory3.c中我们可以分配多少内存。现在我们很清楚的是Linux可以很聪明的处理内存请求的事情,现在我们每次只分配1K内存,并且写入我们所获得的每块内存。
试验--可用内存下面是memory3.c的内容。很自然的,对于系统而言,这个程序是极其不友好的,而且会严重影响一个多用户的机器。如果我们没有意识到这个风险,那么最好是不要运行这个程序;如果我们不运行也并不会影响我们对于这个程序的理解。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define ONE_K (1024)
int main()
{
char *some_memory;
int size_to_allocate = ONE_K;
int megs_obtained = 0;
int ks_obtained = 0;
while (1) {
for (ks_obtained = 0; ks_obtained < 1024; ks_obtained++) {
some_memory = (char *)malloc(size_to_allocate);
if (some_memory == NULL) exit(EXIT_FAILURE);
sprintf(some_memory, “Hello World”);
}
megs_obtained++;
printf(“Now allocated %d Megabytes\n”, megs_obtained);
}
exit(EXIT_SUCCESS);
}
这一次程序的输出结果如下所示:
$ ./memory3
Now allocated 1 Megabytes
...
Now allocated 377 Megabytes
Now allocated 378 Megabytes
Out of Memory: Killed process 2365
Killed
而这一次程序结束了。程序的运行也只是花费了几秒,而且在接近机器实际物理内存的时候会慢下来,而且很明显的使用硬盘。然而,程序已经分配了大于机器中实际物理内存的内存数量。最后系统阻止这个有侵害性的程序并且将其杀掉。在一些系统上,程序只会在malloc调用失败时简单的退出。
工作原理程序所分配的内存是由Linux内核所管理。每次程序要求分配内存并且试着对所分配的内存进行读写操作,Linux内核会接过管理权并且决定如何处理这些请求。
最初,内核只是简单的使用空闲的物理内存来满足程序的内存分配请求,但是一旦内存用光,他就会使用所谓的交换空间。在Linux系统上,这个是一个系统安装时所分配的独立的磁盘空间。如果我们熟悉Windows,Linux交换空间的作用有点类似于隐藏的Windows交换文件。然而,与Windows不同的是,在代码中我们并不需要担心局部堆,全局堆,或是可丢弃的内存段--Linux内核会替我们管理这些。
内核会在物理内存和交换空间中移动数据与程序代码,从而每次我们读写内存时,数据看起来都像是在物理内存中一样,而实际上,这些数据是在我们试图访问他们之前进行定位的。
更为深入的来说,Linux实现了一个虚拟页面内存系统。所有由用户程序员所看到的内存都是虚拟的;也就是说,他并不实际存在于用户所用的物理地址中。Linux将所有的内存划分为页,通常一页为4096字节。当一个程序试图访问内存时,就会进行一个虚拟内存到物理内存的转换,尽管其实现以及其所需要的时间依赖于我们所使用的实际硬件。当所访问的内存并不是实际的物理内存时,就会产生页面失效,并且将控制权传递给内核。
Linux内核会检测正在访问的地址,如果他是一个合法的程序地址,内核就会确定哪一页物理内存是可以访问的。然后内核会分配内存,如果以前并没有向此页内存写入任何数据,或者,此页内存存在于交换空间的磁盘中,就会将包含相应数据的内存页面读入到物理内存中(也许需要将一页移出磁盘)。然后,在映射虚拟内存地址来匹配物理地址之后,内核允许用户程序继续运行。Linux程序并不需要担心这些活动,因为这些实现完全隐藏在内核中。
事实上,当程序用尽物理内存与交换空间,或进超出最大的堆栈尺寸时,内核最后就会拒绝额外的内存申请,并且也许会预先结束这个程序。
所以这对于程序的编写者来说意味着什么呢?最基本的,所有的都是好消息。Linux十分善于管理内存,并且允许程序使用大容量的内存甚至是大块的单独内存空间。然而,我们需要清楚的就是分配两块内存并不会得到一块连续的内存地址。我们所得到的就是我们所请求的:两块单独的内存空间。
那么这样是否显得对于内存的支持有限,而杀死进程是否意味着没有必要检测malloc的返回结果呢?当然不是。在C程序中使用动态分配内存最经常遇到的一个问题是在超出所分配内存的空间写入数据。当出现这种情况时,程序并不会立即退出,但是我们很可能已经覆盖了malloc库例程内部所使用的某些数据。
通常,malloc的调用结果会失败,原因并不在于没有内存可供分配,而是因为内存结构已经被破坏。这些问题很难被追踪,而且在程序,越早检测到错误,就会有更好的机会来追踪原因。在第10章,调试与优化,我们会讨论一些工具可以帮助我们追踪内存问题。
滥用内存假设我们试图使用内存做些坏事。在下面的程序memory4.c中,我们分配一块内存,然后试图在超出内存结束位置的地方写一些数据。
试验--滥用内存
#include <stdlib.h>
#define ONE_K (1024)
int main()
{
char *some_memory;
char *scan_ptr;
some_memory = (char *)malloc(ONE_K);
if (some_memory == NULL) exit(EXIT_FAILURE);
scan_ptr = some_memory;
while(1) {
*scan_ptr = ‘\0’;
scan_ptr++;
}
exit(EXIT_SUCCESS);
}
其输出结果如下:
$ /memory4
Segmentation fault (core dumped)
工作原理Linux内存管理系统会保护系统的其余部分不受内存滥用的影响。为了保证一个行为奇怪的程序不会损害其他程序,Linux会结束这个程序。
在Linux系统上运行的第一个程序只会看到其自己的内存映射,这与其他程序的内存映射是不同的。只有操作系统知道物理内存是如何安排,并且不仅为用户程序管理内存,而且会在用户程序之间起到保护的作用。
分享到:
相关推荐
* 一级:重要敏感数据,如客户肖像库、信息库、财务数据等,这些数据需要严格管理和保护,以免泄露造成经济损失或法律问题。 * 二级:非敏感重要数据,如公司系统数据、业务结果数据等,这些数据需要适当管理和保护...
数据中台之主数据管理 数据中台之主数据管理是指在数据中台中对主数据的统一管理和维护,确保主数据的唯一性、规范性和高效性。主数据管理的目标是统一数据标准和规范,确保主数据的权威性和可靠性,提高数据维护...
《信通院数据资产管理实践白皮书6.0》是数据管理人员、IT专业人士、企业决策者以及对数据驱动决策感兴趣的学者和研究人员的宝贵资源,旨在帮助组织更好地理解和利用其数据资产,实现数据的最大价值
该指南包括三个目标:一是为数据管理工作提供指导原则,并说明如何在数据管理功能领域应用这些原则;二是为数据管理实践的实施提供功能框架;三是为数据管理概念建立通用词汇表。其中,数据管理职能包括数据治理、...
数据资产管理是一款基于 WEB 方式的元数据管理工具,采用这个工具能够整合游离于 企业各环节的元数据资产,便于用户浏览及分析元数据。数据资产管理平台有助于帮助用户 了解和管理信息和加工处理过程的来源,也有...
资产治理旨在降低数据管理的成本并提高效率。具体措施包括: 1. 数据存储治理,形成闭环,确保数据的稳定性和可访问性。 2. 数据计算治理工具,通过工具赋能资产治理,提升治理效率。 3. 治理领域和方法策略,制定...
综上所述,高校教务管理系统数据设计与数据流图的构建是一项复杂而细致的工作,需要充分理解教育管理业务流程,合理规划数据结构,有效描绘数据流动路径,以实现高效、准确的信息管理。通过科学的数据设计,我们可以...
8. 报废设备数据管理:报废设备中的数据应备份后清除,废弃介质妥善处理,防止信息泄露。 9. 计算机病毒管理:设立专人负责防病毒工作,建立防治制度,定期检查和清除病毒。 10. 专用计算机管理:营业用计算机不得...
主数据管理实践白皮书是一份由多个组织合作撰写的文档,它旨在普及主数据管理(Master Data Management,MDM)的知识,并通过最佳实践案例推广其在不同行业中的应用。这份白皮书详细阐述了主数据的定义、重要性以及...
产品是一款基于 WEB 方式的元数据管理工具,采用这个工具能够整合游离于企业各环 节的元数据资产,便于用户浏览及分析元数据。产品有助于帮助用户了解和管理信息和加工 处理过程的来源,也有助于用户理解信息与加工...
普元元数据管理系统是基于CWM(公共仓库元模型)规范的企业级...是目前业内支持全中文内核的一款重量级产品,支持企业元数据管理系统的快速部署、支持与企业现 有认证系统的无缝集成。 已经取得在多家银行成功实践的经
数据资产管理的核心内容可以概括为以下几点:首先,数据治理是数据资产管理的基础,它需要明确数据的责任归属、制定数据管理流程和规范、保证数据的安全性与合规性;其次,数据资产共享是数据价值实现的重要途径,...
例如,在“查询管理员信息”过程中,可以从“管理员数据库”读取数据,并显示在界面上供管理员查看。 #### 五、绘制数据流程图的原则 1. **清晰性**:DFD应尽可能简洁明了,避免过多的细节导致复杂难懂。 2. **...
数据质量管理平台的建设目标是建立一个高效、可靠的数据质量管理平台,提高数据的质量和可靠性,满足业务需求。 五、业务方案 数据质量管理平台的业务方案包括: 1. 系统架构:数据质量管理平台的系统架构包括...
本篇文章将详细介绍一个简单的教务管理系统中的0层和1层数据流图,以及相关的数据字典。 #### 二、0层数据流图解析 0层数据流图通常用于概述整个系统的外部视图,展示系统与外部实体之间的交互情况。 ##### 1. ...
仓库管理系统数据流图是一种用于描述系统中数据如何流动和处理的图表工具,它在IT行业中尤其是在软件设计和系统分析中广泛应用。数据流图通过图形化的方式展示了数据在系统中的运动路径,帮助理解系统的功能和信息...
伴随着大数据、云计算、移动化等先进技术的应用和推广,主数据管理在这个词在企业信息管理领域经常被谈起,且目前SAPMDM是一个较新的模块,国内对于熟练掌握该模块的顾问需求量日益增大 介绍SAPMDM产品的第一本...
在给定的“简单的图书管理系统数据流图”中,我们可以看到图书管理系统的核心流程以及一个附加的工资管理系统流程。 图书管理系统主要包含以下几个部分: 1. **读者管理**:这部分涉及读者信息的管理和维护,包括...
图书管理系统是一种常见的信息系统,用于管理和跟踪图书馆中的书籍信息,包括借阅、归还、库存管理等活动。本系统采用C#编程语言实现,提供了完整的文档,包括数据流图、数据流程图、数据字典、ER图以及模块ER图,...