易语言-探索内存

 

探索内存

数据是如何存在内存当中的:

变量在内存中是有一个地址,变量地址指的是该变量在内存中的地址。

而变量数据地址指的是该变量中数据在内存中的地址。

数据拥有类型,根据不同的类型以不同的长度存储在内存中。

系统如何取出这些数据

数据存在内存当中后会有一个地址,通过这个地址来找到对应的数据。

取变量地址

返回指定变量的内存地址(在内联汇编代码中可以在执行本命令后立即检查EAX寄存器获得),整数型。如欲修改该地址处内容(尤其是文本型、字节集型或复合数据类型变量),请谨慎操作,否则很可能造成内存垃圾或程序崩溃。

1
参数:欲获取其地址的变量,通用型,变量或变量数组。

示例:

取变量数据地址

取指定变量中数据的内存地址。返回值为0表示没有取到变量地址。

  1. 对文本型或字节集型变量而言,如果其长度为0,将返回0;
  2. 对数组变量而言,如果其成员数为0,也将返回0。
  3. 对于文本型或字节集型变量,返回值为文本数据或字节集数据的地址。
  4. 其它情况下,本命令与“取变量地址”具有相同的返回值。

注意:一旦变量超出其作用域范围,或文本型/字节集型变量被重新赋值,或数组变量被重新赋值,先前取到的变量地址将变成无效地址,再对该地址进行读写操作很有可能导致程序崩溃。

1
参数:取变量数据地址,通用型,变量或变量数组。

示例:

申请内存

告诉计算机,申请出一块内存,申请后,我们可以直接向内存中写入数据。

申请后会返回内存地址。

用到的命令:特殊功能支持库中的申请内存命令。

1
2
3
说明:向易语言运行时系统申请指定大小的内存区域。执行成功返回申请到的内存首地址,失败返回0。由本命令申请的内存必须通过“释放内存”命令释放。
第一个参数:欲申请的内存字节数,整数型。
第二个参数:是否清零,逻辑型,注明:如果本参数为“真”,则将申请到的内存区域全部以0填充。如果省略本参数,默认为“假”。

注:因为申请出来的内存可能之前恰好被其他程序用过,里面有上一次的残留数据,这时候就可以通过第二个参数决定要不要把它的内存清空。

示例:

通过示例可以看出是有上一次残留数据的,所以说用内存之前需要先检查或者直接清空。

当第二个参数为时就会清空,清空后就是空文本了,是以0填充的,因为0是文本的结束符,但是是有这个长度的。

写到内存并读取

上面已经申请好内存了,接下来就可以往内存里写入数据了。

用到的命令:系统核心支持库中的写入内存命令。

1
2
3
4
说明:将数据写出到指定的内存区域,注意调用本命令前一定要确保所提供的内存区域真实有效。
第一个参数:欲写到内存的数据。通用型(数组/非数组)。说明:参数值只能为基本数据类型数据或字节数组。
第二个参数:内存区域指针。整数型。说明:本参数提供欲写向内存区域首地址的指针值(就是内存地址)。
第三个参数:内存区域尺寸。整数型。说明:本参数提供该内存区域的有效尺寸,如果欲写出数据超出此尺寸值,将被自动切除。参数值如果为 -1 ,则表示此内存区域尺寸不受限制。如果本参数被省略,则默认值为 -1(可以填写申请内存写的最大长度或者当前数据的长度,如果写入的数据比最大长度短就可以填写-1)。

用到的命令:系统核心支持库的指针到文本命令。

1
2
说明:返回指定内存指针所指向地址处的文本,就是将内存地址中的文本数据输出出来。
参数:内存文本指针。整数型。说明:本参数提供指向一个以零字符结束的文本串内存指针值。

示例:

释放内存

当这个内存操作完后或不在需要了,就需要释放内存,因为程序的内存是有限的,所以说不在使用的内存一定要删除,也就是释放内存。

用到的命令:特殊功能支持库中的释放内存命令。

1
2
说明:释放由“申请内存”所获取的内存区域。内存区域被释放后,不允许再进行读写操作。
参数:欲释放的内存地址。整数型。说明:本参数应当是“申请内存”命令的返回值。

示例:

释放完后的内存地址,在输出这个地址的内容时就是乱码了,如下:

可能刚一释放其他程序就恰巧申请到了这个内存地址,往这个内存中写入了数据,所以说释放之后的内存就不能在使用了。

整数是如何存在内存当中的

接下来申请一个内存,将整数5000写入进去,然后通过指针到字节集查看它是如何存在内存当中的。

用到的命令:系统核心支持库中的指针到字节集命令。

1
2
3
4
说明:返回指定内存指针所指向地址处的一段数据,注意调用本命令前一定要确保所提供的内存地址段真实有效。返回的数据类型为字节集。
本命令的最佳使用场合就是在易语言回调子程序和易语言DLL公开子程序用作获取外部数据。
第一个参数:内存数据指针。整数型。本参数提供指向一个内存地址的指针值。。
第二个参数:内存数据长度。整数型。本参数提供该内存地址处所需获取的数据长度。

示例:

通过下图可以看出这个数据在内存当中的存储方式。

由于短整数是2个字节,所以说136和19就是整数5000的存储情况。

什么是缓冲区

缓冲区实际上就是一块内存,可以被读写的。

因为有的api函数在调用的时候需要传递的参数是缓冲区,如GetWindowTextA 这个函数,它的第二个参数就需要传递一个缓冲区。

api函数GetWindowTextA :

第一种使用方法:

接下来看一下如何使用,首先需要创建一个文本型变量,然后用取空白文本命令,这个命令相当于申请了一块内存,里面保存的都是空格(不是空字符)。

用到的命令:系统核心支持库中的取空白文本命令。

1
2
说明:返回具有指定数目半角空格的文本。
参数:重复次数。整数型。

第二种使用方法:

用申请内存来进行使用,演示如下:

这里有一点需要注意:需要将dll命令中的缓冲区的参数类型改成整数型。

小问题:为什么这个dll命令的第二个参数可以是文本型也可以是整数型?

因为这个缓冲区要的是一个内存地址,不需要去管是何类型的。

这个类型改成字节集也是可以了,只要用取空白字节集就可以了,因为它只是负责往这块内存中取写数据,毕竟写内存的时候实际上是不区分数据类型的。

小问题:取空白文本用不用释放内存?

取空白文本是不需要释放内存的,因为它是在这个局部变量当中的,是栈内存,会自己去释放。

我们申请出来的内存是堆内存,是由系统管理的,它只管申请不管释放,所以需要手动释放。

实际上内存是分堆和栈两部分的,堆指的是我们这种手动申请的内容,栈指的是参数、返回值以及变量。栈内存是由系统自动去开辟的空间。