搜索
查看
编辑修改
首页
UNITY
NODEJS
PYTHON
AI
GIT
PHP
GO
CEF3
JAVA
HTML
CSS
搜索
小小林熬夜学编程
这个屌丝很懒,什么也没留下!
关注作者
热门标签
jquery
HTML
CSS
PHP
ASP
PYTHON
GO
AI
C
C++
C#
PHOTOSHOP
UNITY
iOS
android
vue
xml
爬虫
SEO
LINUX
WINDOWS
JAVA
MFC
CEF3
CAD
NODEJS
GIT
Pyppeteer
article
热门文章
1
HP MSA存储 raid组坏了2块硬盘的数据恢复方法_hp msa 2040更换硬盘
2
头歌工程实训答案-机器学习篇之手写体识别篇_头歌手写体识别答案
3
linux 查看系统版本及内核_linux 2.6.32
4
为了生活,华为OD待遇确实还不错,确实可以~
5
Docker Desktop 配置阿里云镜像服务_docker desktop配置阿里云
6
【从零学习python 】10.Python条件语句和if嵌套详解_python中else后可以嵌套if语句吗
7
STL - string类
8
原来C语言也可以面向对象(一)_c语言代码可以具备面向对象的风格吗
9
宝藏网站推荐-目测当前最强的测试知识库
10
js生成随机数(数字加字母)_js 随机数字字母
当前位置:
article
> 正文
堆,栈,内存泄露,内存溢出介绍_mov byte ptr [ebp-4],cl 汇编
作者:小小林熬夜学编程 | 2024-02-11 15:25:19
赞
踩
mov byte ptr [ebp-4],cl 汇编
转自:
http://freetoskey.blog.51cto.com/blog/1355382/889829
简单的可以理解为:
heap(堆):是由malloc之类函数分配的空间所在地。地址是由低向高增长的。
stack(栈):是自动分配变量,以及函数调用的时候所使用的一些空间。地址是由高向低减少的。
一、预备知识—程序的内存分配
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
二、例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
二、堆和栈的理论知识
2.1申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在栈中的。
2.2申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
2.3申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
2.4申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度,也最灵活
2.5堆和栈中的存储内容
栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
2.6存取效率的比较
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指edx中,在根据edx读取字符,显然慢了。
2.7小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
堆和栈的区别主要分别:
操作系统方面的堆和栈,如上面说的那些,不多说了。
还有就是数据结构方面的堆和栈,这些都是不同的概念。这里的堆实际上指的就是(满足堆性质的)优先队列的一种数据结构,第1个元素有最高的优先权;栈实际上就是满足先进后出的性质的数学或数据结构。
虽然堆栈,堆栈的说法是连起来叫,但是他们还是有很大区别的,连着叫只是由于历史的原因针值读
在计算机科学中,内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。内存泄漏与许多其他问题有着相似的症状,并且通常情况下只能由那些可以获得程序源代码的程序员才可以分析出来。然而,有不少人习惯于把任何不需要的内存使用的增加描述为内存泄漏,严格意义上来说这是不准确的。
一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。应用程序一般使用malloc,calloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。
内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。
这是程序语言中的一个概念,典型的,在C语言中,在分配数组时为其分配的长度是1024,但往其中装入超过1024个数据时,由于C语言不会对数组操作进行越界检查,就会造成内存溢出错误
在程序员设计的代码中包含的“内存溢出”漏洞实在太多了。
导致内存溢出问题的原因有很多,比如:
(1) 使用非类型安全(non-type-safe)的语言如 C/C++ 等。
(2) 以不可靠的方式存取或者复制内存缓冲区。
(3) 编译器设置的内存缓冲区太靠近关键数据结构。
下面来分析这些因素:
1. 内存溢出问题是 C 语言或者 C++ 语言所固有的缺陷,它们既不检查数组边界,又不检查类型可靠性(type-safety)。众所周知,用 C/C++ 语言开发的程序由于目标代码非常接近机器内核,因而能够直接访问内存和寄存器,这种特性大大提升了 C/C++ 语言代码的性能。只要合理编码,C/C++ 应用程序在执行效率上必然优于其它高级语言。然而,C/C++ 语言导致内存溢出问题的可能性也要大许多。其他语言也存在内容溢出问题,但它往往不是程序员的失误,而是应用程序的运行时环境出错所致。
2. 当应用程序读取用户(也可能是恶意攻击者)数据,试图复制到应用程序开辟的内存缓冲区中,却无法保证缓冲区的空间足够时(换言之,假设代码申请了 N 字节大小的内存缓冲区,随后又向其中复制超过 N 字节的数据)。内存缓冲区就可能会溢出。想一想,如果你向 12 盎司的玻璃杯中倒入 16 盎司水,那么多出来的 4 盎司水怎么办?当然会满到玻璃杯外面了!
3. 最重要的是,C/C++ 编译器开辟的内存缓冲区常常邻近重要的数据结构。现在假设某个函数的堆栈紧接在在内存缓冲区后面时,其中保存的函数返回地址就会与内存缓冲区相邻。此时,恶意攻击者就可以向内存缓冲区复制大量数据,从而使得内存缓冲区溢出并覆盖原先保存于堆栈中的函数返回地址。这样,函数的返回地址就被攻击者换成了他指定的数值;一旦函数调用完毕,就会继续执行“函数返回地址”处的代码。非但如此,C++ 的某些其它数据结构,比如 v-table 、例外事件处理程序、函数指针等,也可能受到类似的攻击。
声明:
本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:
https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/75901
推荐阅读
article
Java
byte
转化为
String
_
java
byte
to
string
...
1、Java 中
byte
转化为
String
,代码如下package nice.com.mian;import ja...
赞
踩
article
Java
系列
之:
byte
[]和
string
之间的
转
换_
byte
[]
转
string
...
Java
系列
之:
byte
[]和
string
之间的
转
换一、String
转
化为
byte
[]二、
byte
[]
转
化为
string
...
赞
踩
article
Java
中
byte
[]转
String
问题
_
java
byte
转
string
c0 80
问题
...
最近的项目中要使用到把
byte
[]类型转换成
String
字符串然后通过网络发送,但发现发现出去的字符串和获取的字符串虽然...
赞
踩
article
在
Java
中
byte
[]与
String
相互
转
换
时数据不一致_
java
字符串
转
byte
[]
后
数值不...
当我们将
byte
[]
转
换
成
String
类型
后
再将其
转
换
为
byte
[]时,会发现前
后
byte
[]类型的数据不一致。看以下代...
赞
踩
article
JAVA中3种将
byte
转换为
String
的方法_
java
byte
to
string
...
byte
b = 65;(一)
String
s=Byte.
to
String
(b); (二)
String
s=b + ...
赞
踩
article
Java
中
byte
[] 数组与
String
字符串
的转化_
java
byte
数组转
字符串
返回参...
1.
String
转
byte
[]
String
str = "Hello";//声明一个
字符串
byte
[] srtby...
赞
踩
article
【
java
】
java
中
进制
、
byte
、
String
转换问题_
java
byte
数组
中
数据值为什么和转...
在博主之前的文章
中
,有简单介绍过二
进制
,除了二
进制
,16
进制
也是常用的,例如在博主接触的tcp(modbus)协议
中
1...
赞
踩
article
java
中
byte
[]和
String
相互
转换
_
java
byte
[]
string
互转...
正常来说,
string
要
转换
为
byte
[],直接
string
.getBytes();而
byte
[]
转换
为
string
,则...
赞
踩
article
Java
byte
[] 和
String
互相
转换
_
java
byte
转
string
...
通过用例学习
Java
中的
byte
数组和
String
互相
转换
,这种
转换
可能在很多情况需要,比如IO操作,生成加密hash码...
赞
踩
article
java
byte
[]
转
String
存储_
base64
byte
数组
转
字符串
...
String
base64
String
= Base64.getEncoder().encodeTo
String
(原数据...
赞
踩
article
Java
byte
[]和
String
相互
转换
_
java
string
byte
互相
转换
...
Java
-
byte
[] 和
String
互相
转换
通过用例学习
Java
中的
byte
数组和
String
互相
转换
,这种
转换
...
赞
踩
article
java
string
byte
[] 互相
转换
_
string
byte
互相
转换
...
1、
string
转
byte
[] 1 2 Stringstr="Hello";
byte
[...
赞
踩
article
Java
-
byte
[] 和
String
互相
转换
...
通过用例学习
Java
中的
byte
数组和
String
互相
转换
,这种
转换
可能在很多情况需要,比如IO操作,生成加密hash码...
赞
踩
article
Java
中
byte
与
String
的相互
转化
_
java
byte
string
...
String
转化
为
byte
[]数组
String
str = "asd";
byte
[] bs = str.getBytes...
赞
踩
article
byte
[]
数组
和
String
的相互转化_
s
.get
byte
s
()...
String
转为
byte
[]
数组
:
s
.getByte
s
()
String
s
="01234567890abcdef;byt...
赞
踩
article
Java
字节
流转
字符串
处理
_
返回
接口数据
byte
变成
字符串
了...
字节
流转
字符串
处理public class ByteUtil { public static String
byte
Bu...
赞
踩
article
java
实现
byte
转
字符串
_
java
byte
转
字符串
...
这样需要注意的是每两个字符互换了,我这里的原因是modbus tcp通讯读取出来的数据需要互换 private sta...
赞
踩
article
java
byte
.
tostring
_
Java
Byte
toString
()用法及代码示例...
Byte
类的
toString
()方法是
Java
中的内置方法,用于返回String值。public String toSt...
赞
踩
article
java
byte
.
tostring
_
Java
中如何正确的将
byte
[]
数组
转化为
String
类型?...
很多人在编程时,总是喜欢用一下方法将
数组
转为字符串:(a为
byte
数组
)
String
s=a.to
String
();可是...
赞
踩
相关标签
Java系列
byte[]
string
java
开发语言
后端
字符串
bytearray
Java
byte
String
java byte.tostring