内存分配详解 malloc, new, HeapAlloc, VirtualAlloc,GlobalAlloc
很多地方都会使用内存,内存使用过程中操作不当就容易崩溃,无法运行程序,上网Google学习一下,了解整理下他们之间的区别以及使用 ,获益匪浅
0x01 各自的定义和理解
(1)先看GlobalAlloc()
GlobalAlloc()主要用于Win32应用程序实现从全局堆中分配出内存供2017-03-05程序使用,是16位WINDOWS程序使用的API,对应于系统的全局栈,返回一个内存句柄,在实际需要使用时,用GlobalLock()来实际得到内存 区。但32位WINDOWS系统中全局栈和局部堆的区别已经不存在了,因此不推荐在Win32中使用该函数,应使用新的内存分配函数HeapAlloc()以得到更好的支持,GlobalAlloc()还可以用,主要是为了 兼容。
一般情况下我们在编程的时候,给应用程序分配的内存都是可以移动的或者是可以丢弃的,这样能使有限的内存资源充分利用,所以,在某一个时候我们分配的那块 内存的地址是不确定的,因为他是可以移动的,所以得先锁定那块内存块,这儿应用程序需要调用API函数GlobalLock函数来锁定句柄。如下: lpMem=GlobalLock(hMem); 这样应用程序才能存取这块内存。所以我们在使用GlobalAllock时,通常搭配使用GlobalLock,当然在不使用内存时,一定记得使用 GlobalUnlock,否则被锁定的内存块一直不能被其他变量使用。
GlobalAlloc对应的释放空间的函数为GlobalFree。
(2)HeapAlloc()
HeapALloc是从堆上分配一块内存,且分配的内存是不可移动的(即如果没有连续的空间能满足分配的大小,程序不能将其他零散的 空间利用起来,从而导致分配失败),该分配方法是从一指定地址开始分配,而不像GloabalAlloc是从全局堆上分配,这个有可能是全局,也有可能是 局部
(3)malloc()
是C运行库中的动态内存分配函数,主要用于ANSI C程序中,是标准库函数。WINDOWS程序基本不再使用这种方法进行内存操作,因为它比WINDOWS内存分配函数少了一些特性,如整理内存
(4)new
标准C++一般使用new语句分配动态的内存空间,需要申请数组时,可以直接使用new int[3]这样的方式,释放该方法申请的内存空间使用对应的delete语句,需要释放的内存空间为一个数组,则使用delete [] ary;这样的方式。
要访问new所开辟的结构体空间,无法直接通过变量名进行,只能通过赋值的指针进行访问.
new在内部调用malloc来分配内存,delete在内部调用free来释放内存。
(5)
(1) VirtualAlloc 下面是网友的解释 但我个人的理解这个才是内存申请的鼻祖,所有的内存的申请都感觉默认调用了它
PVOID VirtualAlloc(PVOID pvAddress, SIZE_T dwSize, DWORD fdwAllocationType, DWORD fdwProtect)
VirtualAlloc是Windows提供的API,通常用来分配大块的内存。例如如果想在进程A和进程B之间通过共享内存的方式实现通信,可以使用该函数(这也是较常用的情况)。不要用该函数实现通常情况的内存分配。该函数的一个重要特性是可以预定指定地址和大小的虚拟内存空间。例如,希望在进程的地址空间中第50MB的地方分配内存,那么将参数 50*1024*`1024 = 52428800 传递给pvAddress,将需要的内存大小传递给dwSize。如果系统有足够大的闲置区域能满足请求,则系统会将该块区域预订下来并返回预订内存的基地址,否则返回NULL。
使用VirtualAlloc分配的内存需要使用VirtualFree来释放。
0x02 区别与联系
它们之间的区别主要有以下几点:
1、GlobalAlloc()函数在程序的堆中分配一定的内存,是Win16的函数,对应于系统的全局栈,而在Win32中全局栈和局部堆的区别已经不存在了,因此不推荐在Win32中使用该函数。
2、malloc()是标准库函数,而new则是运算符,它们都可以用于申请动态内存。
3、new()实际上调用的是malloc()函数。
4、new运算符除了分配内存,还可以调用构造函数,但是malloc()函数只负责分配内存。
5、对于非内部数据类型的对象而言,只使用malloc()函数将无法满足动态对象的要求,因为malloc()函数不能完成执行构造函数的任务。
6、malloc(); 和 HeapAlloc(); 都是从堆中分配相应的内存,不同的是一个是c run time的函数,一个是windows系统的函数, 对于windows程序来说,使用HeapAlloc();会比malloc();效率稍稍高一些。
0x03关于内存的初始化和使用
1、内存分配方式
内存分配方式有三种:
(1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在
。例如全局变量,static变量。
(2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存
储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自
己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
2.内存使用错误
发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误,通常是在程序运行时才能捕捉到。
而这些错误大多没有明显的症状,时隐时现,增加了改错的难度。有时用户怒气冲冲地把你找来,程序却没有
发生任何问题,你一走,错误又发作了。 常见的内存错误及其对策如下:
* 内存分配未成功,却使用了它。
编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查
指针是否为NULL。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。
* 内存分配虽然成功,但是尚未初始化就引用它。
犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值
错误(例如数组)。 内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不
可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。
* 内存分配成功并且已经初始化,但操作越过了内存的边界。
例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞
错,导致数组操作越界。
* 忘记了释放内存,造成内存泄露。
含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次
程序突然死掉,系统出现提示:内存耗尽。
动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误
(new/delete同理)。
* 释放了内存却继续使用它。
有三种情况:
(1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新
设计数据结构,从根本上解决对象管理的混乱局面。
(2)函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函
数体结束时被自动销毁。
(3)使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。
【规则1】用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存
【规则2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
【规则3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。
【规则4】动态内存的申请与释放必须配对,防止内存泄漏。
【规则5】用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。
这些都是我查阅资料的整理 希望会有所帮助
内存分配详解 malloc, new, HeapAlloc, VirtualAlloc,GlobalAlloc的更多相关文章
- Java学习之二维数组定义与内存分配详解
二维数组:就是元素为一维数组的一个数组. 格式1: 数据类型[][] 数组名 = new 数据类型[m][n]; m:表示这个二维数组有多少个一维数组. n:表示每一个一维数组的元素有多少个. 注意: ...
- java程序运行时内存分配详解
java程序运行时内存分配详解 这篇文章主要介绍了java程序运行时内存分配详解 ,需要的朋友可以参考下 一. 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个 ...
- [Java]Java类和对象内存分配详解
描述 代码说明: 一.当Person p1 = new Person();第一次被调用时需要做两件事: 1.先判断类加载器是否加载过Person类,如果没有则加载到Person类型到方法区 2.在堆中 ...
- C++中内存分配详解
转载自51CTO.com http://developer.51cto.com/art/201107/276154.htm 我们都知道,内存基本上分为静态存储区.堆区和栈区三大部分 ...
- java程序运行时内存分配详解 (转)
转自:http://www.tuicool.com/articles/uU77v2 一. 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Ja ...
- Java虚拟机内存分配详解
简介 了解Java虚拟机内存分布的好处 1.了解Java内存管理的细节,有助于程序员编写出性能更好的程序.比如,在新的线程创建时,JVM会为每个线程创建一个专属的栈 (stack),其栈是先进后出的数 ...
- JAVA中堆栈和内存分配详解(摘抄)
在Java中,有六个不同的地方可以存储数据: 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存 ...
- java运行时内存分配详解
一. 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Java进程对应唯一一个JVM实例,每一个JVM实例唯一对应一个堆,每一个线程有一个自己私 ...
- C++ 类的实例中 内存分配详解
一个类,有成员变量:静态与非静态之分:而成员函数有三种:静态的.非静态的.虚的. 那么这些个东西在内存中到底是如何分配的呢? 以一个例子来说明: #include"iostream.h&qu ...
随机推荐
- mysql查询不区分大小写
摘自:http://www.jb51.net/article/70884.htm 当我们输入不管大小写都能查询到数据,例如:输入 aaa 或者aaA ,AAA都能查询同样的结果,说明查询条件对大小写不 ...
- AngularJS(四)——ng-controller(控制器)
前言 上篇大概说了一下指令的应用格式以及创建自定义指令方法,本篇重点介绍一些ng-controller都有哪些小作用. 内容 通过修改控制器部分,修改显示界面. Demo <div ng-app ...
- B君的第九题
B君的第九题 对于一个排列\(a_1, a_2,\dots,a_n\),如果对于一个i满足\(a_{i-1}<a_i>a_i+1\)则称i是一个极大值.我们认为\(a_0=a_{n+1}= ...
- ReentranLock实现原理
原文链接:https://blog.csdn.net/jeffleo/article/details/56677425 一.ReentranLock 相信我们都使用过ReentranLock,Reen ...
- 《图解HTTP》阅读笔记--第七章---确保WEB安全的HTTPS
第七章.确保WEB安全的HTTPSHTTP的缺点:通信使用明文(不加密),内容可能会被窃听 解决---加密处理: //将通信加密 :通过SSL(安全套接层)---HTTPS(超文本传输安全协议)--- ...
- typeof 和 instanceof
typeof 和 instanceof 都是用来判断类型的函数 typeof 对于原始类型来说,除了 null 都可以显示正确的类型 typeof 1 // 'number' typeof '1' / ...
- Python之将字符串转换为字节的两种方法
s = '你是谁' a = bytes(s,'utf-8') # ==> 得出的 a 的结果就是对应的字节 s.encode('utf-8') # ==> 该命令将字符串转换为字节形式
- Qt 学习之路 2(1):序
https://www.devbean.net/category/qt-study-road-2/page/10 原来开过QT学习之路1, 很棒, 再翻阅时已经没有了. 所以这次把看过的记录下来 Ho ...
- python解释器安装
1. 下载安装包 1 2 https://www.python.org/ftp/python/2.7.14/python-2.7.14.amd64.msi # 2.7安装包 https: ...
- List<T> 循环修改其中的数据
List<MyObject> myObject = new List<MyObject>(); myObject.ForEach(w => { w.字段1=123: if ...