您的位置:首页 > 编程语言 > C语言/C++

[c++,kernel] 获取当前进程内存占用量

2014-11-30 10:50 155 查看
实验目的:

通过系统调用实现获取当前正在运行的进程占用系统中的内存资源的最大值,

由于涉及到系统库中的API 所以将其归类为kernel方向。

实验思路:

希望本程序可以被 windows 和 linux/unix 所兼容,所以编程实现时过程中通过宏定义

方法来判断当前平台类型,然后根据不同的平台类型调用不同的系统 API 来得到系统的参数。

但是在代码中仅给出 window 下面的代码及说明(使用 #ifdef 来分辨平台在 vs2012 中没有调试成功)

实验环境:

vs2012 , c++

实验代码:

//memChecker.h

#ifndef   MEMCHECKER_H
#define  MEMCHECKER_H

namespace memChecker
{
long get_maxMem_kb () ;
}
#endif //MEMCHECKER_H


//memChecker.cpp

#include "memChecker.h"

#include <Windows.h>
#include <Psapi.h>

using namespace memChecker;

long memChecker::get_maxMem_kb()
{
PROCESS_MEMORY_COUNTERS pmc ;
GetProcessMemoryInfo(GetCurrentProcess() , &pmc, sizeof(pmc));
return pmc.PeakWorkingSetSize / 1024 ;
}


//Main.cpp

#include <cstdio>
#include <cstdlib>
#include <iostream>

#include "memChecker.h"

using namespace std ;

int main ( int argc , char * argv [] )
{
cout<<"here is the current maxmum memory "<<endl;
long usage = memChecker::get_maxMem_kb() ;

cout<<usage<<endl ;

system("pause") ;
return 0 ;
}


其中,对于 memChecker.cpp 中所涉及到的 windows 内核代码注释如下:
1. 变量 PROCESS_MEMORY_COUNTERS

1.
PROCESS_MEMROY_COUNTERS

typedef struct _PROCESS_MEMORY_COUNTERS
{
DWORD cb ;
DWORD PageFaultCount ;
SIZE_T    PeakWorkingSetSize ;
SIZE_T    WorkingSetSize ;
SIZE_T    QuotaPeakPagePoolUsage ;
SIZE_T    QuotaPagedPoolUsage ;
SIZE_T     QuotaPeakNonPagedPoolUsage ;
SIZE_T    QuotaNonPagedPoolUsage ;
SIZE_T     PagefileUsage ;
SIZE_T    PeakPagefileUsage ;
} PROCESS_MEMORY_COUNTERS , *PROCESS_MEMORY_COUNTERS ;

PROCESS_MEMORY_COUNTERS
这个变量是用来记录系统中当前进程,也就是 PROCESS_MOMORY_COUNTERS
变量所在的这个程序运行起来之后对应的这个进程对系统内存资源的使用量的一系列统计数据。

其中 DWORD 是一个 Microsoft  中定义的一个变量类型,
可以将它看作是一个类似于char 类型,不过 char 对应的是一个字符号,
而DWORD 是 double word ,每个 word 是 2个字节的大小, 那么DWORD 就是长度为 4 个字节大小的一个变量类型。

而SIZE_T 是属于c++标准库中的一个类型, 他是一个与机器相关的无符号的类型(unsigned)。

1. cb:
以字节为单位用来记录 当前这个 PROCESS_MEMORY_COUNTERS 类型对应的变量
所占的大小,即
PROCESS_MEMORY_COUNTERS pmd ;
pmd.cb = sizeof(pmd) ;

2. PageFaultCount:
用来记录发生页错误的次数

3. PeakWorkingSetSize
以字节为单位,用来记录当前工作集的大小

4. QuotaPeakPagedPoolUsage
以字节为单位,记录分页池中最大的使用量

5. QuotaPagedPoolUsage
以字节为单位,记录当前分页池中的使用量(即分页池中被进程申请的全部页面的大小(kb))

6. QuotaPeakNonPagedPoolUsage
以字节为单位记录非分页池中最大的空间申请量

7. QuotaNonPagedPoolUsage
以字节为单位,记录非分页池中当前空间的申请使用量
(注: 这里的空间均是指系统中的内存空间 ;我想:在分页池中空间的分配是以 页面为单位的,
而在非分页池中内存空间的分配大小是由申请空间大小来分配的)

8.PagefileUsage
commit charge is a term used in Microsoft Windows operating systems to describe
the total amount of pageable virtual address space for
which no backing store is assigned other than the pagefile.
<这里的 commit charge 是内存的一种: 在微软的操作系统中时用来描述所有可分页虚拟地址空间的总数目,
其中这些虚拟地址空间中全部是是页面文件存放空间,而不包含缓存空间(backing store)>

而这个PagefileUsage 是以字节为单位来记录当前进程所占用的 Commit Charge 类型内存的大小数值的。
Commit Charge 在官网中也给出解释,说它是有内存管理者为当前正在运行的继承所分配的全部内存的一个总数。

9. PeakPagefileUsage
这个变量是用来以字节为单位记录,系统为当前进程在该进程的生命周期内所分配的
最大Commit Charge类型内存的最大值。


2. method: GetProcessMemoryInfo

2), Mehtod : GetProcessMemoryInfo
从它的名字即可推知它的功能,用来获取明确指定进程
的内存使用情况信息。

这个系统API的设计方式与 unix/linux 常用的系统API 设计方式很相似:
都是通过返回值来返回该方法执行的是否正确的情况,
并且通过 "值-地址" 的传参方式来得到该函数真正的返回数值。
这一点"值-地址" 的传参方式可以从如下的API描述中看出来:
即, _In_ 表示的是,该参数是传入到方法中的数值,
_Out_ 所表示的是,该参数传入的是一个指向空间的地址变量,(指针),
在该函数中得到运行结果之后,通过传入的指针将结果写入到指针所指向的空间中即可。
这样在方法结束返回到主调方法中之后,存放结果的空间并不会随着子方法的运行结束
而被释放掉,主调方法仍旧可以通过刚刚传入到子方法中的指针来对该指针指向空间进行访问。

其中,BOOL 后面的 WINAPI 以意思是表明该函数是 windows中的系统API,
系统 API 并不是系统调用,而是系统为程序员使用系统调用提供的一个接口函数。
在该API中(系统API)调用的是真正的内核中的系统方法,也就是系统调用。

知道这一点十分重要,因为这会直接影响你编写程序所站的角度:

是以一名使用者的身份,还是以计算机的身份。
如果你想修改系统内核代码的话,是必须要站在计算机的身份来思考整个程序的走向的。

反之,如果你只想访问,读取系统当前的某些状态,
那么你必须以使用者的身份来思考问题。

BOOL WINAPI GetProcessMemoryInfo
(
_In_    HANDLE Process ,
_Out_ PROCESS_MEMORY_COUNTERS ppmc,
_IN_  DWORD cb
) ;

其中第一个参数是用来传入想要获取信息的进程对象的句柄,
因为本方法只是想获取当前的进程使用内存的情况,
所以在本方法中调用一个
GetCurrentProcess() 即可得到当前进程的句柄。
这里所说的句柄,类似于对象的一种引用(reference),通过引用可以
确定该对象(该进程)在系统中存放的位置、大小等相关信息。

<在这里我是这么想的(仅仅是推理,没有实际求证):
虽然普通类的引用(reference )于Process 的句柄(handler )亦或是一个对象实体的指针(pointer ),
所起到的作用都是相类似的,在这里撇开指针不说,只谈引用和句柄。

二者之所以区分对待,是因为Process 这个数据结构对象是系统内部的数据结构对象,
而引用所指代的应该是用户自定义的类对象,二者占用的内存空间应该是有所区别的。
系统对引用和句柄的维护方式,即其相应的空间回收、访问和管理方式有所不同的原因>

1.Process : [传入参数] 接收要分析占用内存空间信息的进程对象的句柄
2.ppmc:[传入、传出参数] 接收指向 PROCESS_MEMORY_COUNTERS 结构体对象的指针
通过传入的指针将分析结果记录到该指针指向的空间中,方法结束空间不会被回收
(空间是由系统为主调方法分配的,而并非是 GetProcessMemoryInfo 方法中的局部变量占用的空间)
3. cb       :[传入参数] 该数值用来描述 PROCESS_MEMORY_COUNTERS 实体指针所指向的实体占用空间的大小。
即 cb = sizeof (*pmd ) ; 或是 cb = (*ppmc)->cb ;


3. Method :GetCurrentProcess
3).Method:  GetCurrentProcess()

HANDLE WINAPI GetCurrentProcess (void ) ;

该方法是 windows 中的系统API , 返回值是当前正在运行的进程的句柄对象。
那什么叫做当前运行的进程呢? 就是你调用该 GetCurrentProcess() 语句所在的程序,
在该程序被运行起来之后,对于 GetCurrentProcess () 而言就是它的当前正在运行的进程。


实验不足与改进:

这个代码中不能加入自动识别运行平台的宏定义,很是遗憾没能够写上 linux 访问内存使用信息的系统函数。

宏定义还需要在仔细学习一下。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: