上一篇提到了 绑定
中的 类型绑定
。
这篇说说存储绑定,程序设计语言的一种根本特征取决于这种语言的变量存储绑定的设计方式。
变量名
与 存储单元 之间的关联的这个过程称为 存储绑定
,或称为 存储空间分配。
变量名与存储单元的解除绑定的这个过程称为 存储空间解除绑定
。
变量的 生存期
指该变量名被绑定于某一存储地址的时间。或者说一个变量名与某一存储地址从绑定到解除绑定的这段时间。
由此可见,变量的生存期与存储绑定紧密相连
。
一般为了分析变量的存储绑定,根据变量的生存期将其分为四种类型:
静态变量(静态分配)
栈动态变量(栈分配)
显示堆动态变量(堆分配)
隐式堆动态变量(堆分配)
有时也粗略的分为三种:静态变量,栈变量 和 堆变量。
一、静态变量
静态变量指在程序运行之前被绑定与某存储单元,一直保持不变直到程序运行结束的变量。
全局变量是静态分配的最典型的例子,数值和字符串也是静态分配的。
此外多数编译器还会生成各种表格,用于运行时的各种支撑例程如排错、动态类型检查、垃圾收集、异常处理等。
这些表格也是静态分配的。
静态分配的一半在一个受保护的只读存储区域,任何由于疏忽而去重写它们的企图都将导致处理器中断。
静态分配的优点:
1、全局变量常常用于程序执行的整个过程,因此将它们绑定与相同的存储空间。
2、让在子程序中声明的变量成为历史敏感的。
3、高效率,静态分配都可以直接寻址,其它类型的变量常常则是间接寻址。间接寻址速度较慢。另静态分配没有运行时分配与解除分配所需的开销
静态分配的缺点:
1、灵活性差,如仅有静态存储绑定的语言不支持子程序递归。
2、变量之间不能共享存储空间。
C/C++中允许在函数内的变量定义中使用static修饰符,使得所定义的变量为静态的。
但static修饰符作用于C++/Java/C#的类定义中的变量时却不是静态变量,这时是类变量。可见同一个保留字的多种用途可能产生混淆,尤其对于初学者。
二、栈动态变量
栈动态分配指当确定它们的声明语句时就产生了存储绑定,但它们的类型是静态绑定的(JS中例外,它的类型也是动态绑定的)。
这个绑定过程发生在程序执行到声明语句所依附的代码时,因此栈动态分配发生在运行时,其存储空间是运行时的栈。
C++/Java/C# 中方法内声明的变量都是栈动态的。而Ada中所有定义于子程序的非堆变量都是栈动态的。
栈动态分配的优点:
1,灵活性好,支持子程序递归
2,变量之间可共享存储空间
栈动态分配的缺点:
效率较低,间接寻址及需要在运行时分配及解除分配
三、显示堆动态变量
堆 是指一组使用了不规则,组织上高度松散的存储单元。
显示堆动态变量 是由程序人员指定特定的指令(如new,delete)来进行分配与解除分配的存储单元。
这些从堆上分配和解除分配的变量只能通过指针或引用变量来引用。
显示堆动态变量 有两个与其关联的变量
指针/引用:只有通过它们才能访问堆动态变量
堆动态变量自身:如N多基本类型变量组成的值自身
如
// java
Person p1 = new Person("name");
// js
var p1 = new Person('name');
使用new操作符进行存储分配,执行后返回指向该堆动态变量的引用,该引用可访问到堆动态变量自身。
如
int *inode;
inode = new int;
delete inode;
使用delete操作符进行解除存储分配,执行delete后解除了存储分配。
C++要求显示的解除分配,而Java/JavaScript则无需,它们采用垃圾回收机制。
C#中既有堆动态分配也有栈动态分配,这两者都是隐式的解除分配。
显示堆动态变量优点:
常用于动态结构,如链表,树等。这些结构需要在运行期间生长或收缩。通过指针或引用及使用显示堆动态变量能方便的构造出这种结构。
显示堆动态变量缺点:
1,难于正确使用指针变量或引用变量。
2,分配及解除分配所需的代价
3,存储管理上的复杂性
四、隐式堆动态变量
隐式堆动态变量 指当它们被赋值时才绑定到堆存储空间。实际上,当它们每次赋值的时候其都会被绑定一次。
如JavaScript中
ary = [33,55];
不管ary之前是否预先被定义使用过,现在它都是一个有两个值的数组。
隐式堆动态变量优点:
高度灵活性,允许编写极为通用的程序。
隐式堆动态变量缺点:
1,效率低,运行时维护所有动态属性的额外开销
2,编译器会遗漏某些错误检查
3,存储管理的复杂性
分享到:
相关推荐
ViewModel的生命周期比Activity和Fragment长,它会在组件的整个生存期内存在,直到组件完全销毁。这样,开发者可以将数据存储在ViewModel中,而不必担心配置改变导致的数据丢失。 实现生命周期绑定的步骤通常包括...
过程的定义(静态)对应于过程的活动(动态),名字的声明(静态)对应于名字的绑定(动态),声明的作用域(静态)对应于绑定的生存期(动态)。 局部数据的布局取决于变量类型和编译器的对齐策略。每个变量在局部...
过程的定义对应于过程的活动,名字的声明对应于名字的绑定,声明的作用域对应于绑定的生存期。这帮助我们理解在编译时和运行时,程序结构是如何映射到实际的存储分配的。 活动记录的常见布局包括返回值、临时数据、...
过程活动的生存期是从开始执行到结束所花费的时间。参数处理则包括形式参数(在过程定义中)和实在参数(在调用时),有多种传递方式,如传地址、传值、得结果和传名。 名字绑定是静态概念与动态概念的结合。在编译...
- **静态局部变量**与普通局部变量的区别在于生存期。静态局部变量在整个程序运行期间存在,即便函数调用结束,其值仍然保留。 - **静态函数**的作用域仅限于当前源文件,这有助于减少命名冲突,增强代码的可读性...
变量的生存期指的是它绑定到特定存储地址的时间。静态变量的生存期从程序开始到结束,而动态变量具有更高的灵活性和额外的开销。类型检查确保了操作符和操作数是兼容的类型,而强类型语言则能始终发现程序中的类型...
活动记录的生存期是其从开始执行到结束的整个时间段,可能包含与其他过程的嵌套调用。 存储分配策略有三种:静态分配、栈式动态分配和堆式动态分配。静态分配在编译时就为数据对象分配固定存储,适合于不需要在运行...
session 对象的生存期从客户首次访问服务器上的 JSP 页面时开始,直到关闭浏览器。 三、session 对象的方法 session 对象有多种方法,包括: 1. getAttribute(String attributeName):返回该会话中与指定名称绑定...
这意味着变量或函数的生存期比普通局部变量更长。 #### Project 工程 在软件开发中,“project”指的是一组相互关联的文件和资源的集合,这些文件和资源被组织在一起以构建一个完整的应用程序或库。 #### Setting ...
9.5 变量的作用域和生存期 316 9.6 泛型 317 9.7 本章小结 318 9.8 练习 319 第10章 组件化 321 10.1 代码与内容的分离 322 10.2 代码与设计的分离 323 10.3 后台代码 323 10.3.1 Page指令 324 10.3.2 不...
13. **ViewModel**:生存期跨越配置变更,用于保持与UI相关的数据。 14. **Kotlin协程(Coroutines)**:在Android中实现后台任务,避免回调地狱,提升代码可读性。 15. **Room Persistence Library**:简化SQLite...
- **局部变量**:仅在定义它的函数或代码块内有效,存储在栈中,生存期始于进入函数或代码块,终于退出。 7. **寄存器、寻址和内存管理**: - 寄存器是CPU内部的高速存储单元,用于暂存运算过程中的数据和指令。...
- 存储用户特定变量,生存期为会话期间,或超时设置,默认20分钟。 29. **Cookie对象**: - 存储客户端信息,通过HttpCookie类创建和使用。 30. **SQL基本操作**: - SELECT查询,INSERT插入,UPDATE更新,...
4. **高速缓存与生存期**: 为了提高效率,主机通常会将最近使用的IP-MAC映射存储在高速缓存中。若两分钟内未使用,表项会被删除。当计算机重启或映射过期时,需重新获取MAC地址。 5. **实验步骤**: - **ARP命令...
一个进程中可以包含多个活动,进程的存活时间可能超过单个活动的生存期。 2. **Android开发工具的使用**: - 在DOS命令行中,可以使用Android SDK提供的工具,如adb(Android Debug Bridge)进行设备通信,dx用于...
同样地,static局部变量的存储方式从栈转换成了静态存储,其生存期从函数调用的生命周期变成了整个程序的生命周期。static函数只能被所在模块的其他函数调用,限制了函数的作用范围,增强了模块化。 在阅读《C终极...
- **生存期**:`static` 局部变量具有静态生存期,即使函数退出后仍保留值。 9. **`static` 函数与普通函数的区别** - **作用域**:`static` 函数仅在定义它的文件内可见,限制了函数的使用范围。 - **内存占用*...