堆栈

Keil C51里关于堆栈指针的处理

假如想象 提交于 2019-12-15 20:44:59
Keil C是非常优秀的C51编译器,可能是最好的C51编译器,提供各种优化模式,对变量的优化和地址安排做得非常好。这是用C语言写代码的好处之一,如果用汇编写,得费一大番功夫给各个变量安排内存物理地址,还得时刻记住哪些地址的内存单元是已经分配了,新增加的变量就不能占用那些已经分配了的单元,以免产生内存交叠冲突和溢出。我一直非常信赖Keil C51的编译结果,在我的印象里,它对内存的分配是完美的,只要代码用它编译时没有报告任何warning和error,代码运行时不可能内存冲突或溢出的现象。 但,今天发生的事情证明我错了。 手头上有个产品的代码,代码量很大。程序跑起来的效果不大好,因此打算把代码优化一下。代码量越大,通常可优化的地方也越多。对8051来说,访问芯片内部的data区(0~7FH)内存速度是最快的,直接访问,一条指令就能读写,而idata区(80H~FFH)虽然还是内存区,但由于地址分配上跟特殊寄存器SFR重合,只能间接地址访问,两条指令才能读写,速度稍慢点,而外存xdata区(0~7FFFH)必须使用DPTR指针才能访问,速度是最慢的。很明显,优化的原则就是尽量把频繁读写的变量优先安排在data区,然后是idata区,最后才是xdata区。 当我做完变量手工优化工作后,把编译模式设为SMALL,这样C51编译器会自动把那些我没手工指定存放区的变量优先安排进data区

堆栈与堆栈操作(堆栈也叫做栈)

主宰稳场 提交于 2019-12-15 12:38:35
相关资料参照蒋本珊编著的计算机组成原理(第3版)第63页 堆栈分类 1.硬堆栈(寄存器堆栈)   用一组专门的寄存器构成,若有k-1个寄存器则最多只能压入k个信息,否则将丢失信息。这种堆栈不用设置栈顶指针。 2.软堆栈(存储器堆栈)   寄存器堆栈的成本比较高,不适合作大量的堆栈,而从主存中划出一段区域来作为堆栈是最合算和最常用的方法,这种堆栈叫做软堆栈。堆栈的大小可变,栈底固定、栈顶浮动,需要有一个专门的硬件寄存器作为堆栈的栈顶指针。 (其中,存储器堆栈又分为:自底向上堆栈和自顶向下堆栈) 堆栈操作   参加运算的两个操作输隐含地从堆栈的顶部弹出,送到计算器中进行运算,运算的结果再隐含的压入堆栈。 来源: https://www.cnblogs.com/ahaMOMO/p/12043703.html

使用Spring Boot和AspectJ实现方法跟踪基础结构

删除回忆录丶 提交于 2019-12-14 21:16:33
了解如何使用Spring Boot和AspectJ实现方法跟踪基础结构!最近在优锐课学习收获颇多,记录下来大家一起进步! 在我们的应用程序中,获取方法的堆栈跟踪信息可能会节省很多时间。具有输入输出参数值和方法所花费的时间可以使查找问题变得更加容易。在本文中,我们将研究如何使用Spring Boot,AspectJ和Threadlocal为方法跟踪基础结构实现起点。 在此示例中,我使用了: Spring Boot Starter Web 2.1.7 Java 1.8 + AspectJ 1.8 Maven 3.2 1. 总览 在本教程中,我们将准备一个简单的REST服务,该服务将在书店中检索有关一本书的详细信息。然后,我们将添加一个 ThreadLocal 模型,该模型将在整个线程生命周期中保持堆栈结构。最后,我们将增加一个方面来削减调用堆栈中的方法,以获取输入/输出参数值。让我们开始吧! 项目结构 2. Maven依赖 Spring Boot Starter Web —使用Spring MVC的RESTful服务 Spring — 具备Aspect功能 AspectJ编织者向Java类引入建议 Apache Commons Lang —用于字符串实用程序 1 <parent> 2 <groupId>org.springframework.boot</groupId> 3

函数调用堆栈的过程

帅比萌擦擦* 提交于 2019-12-14 19:09:43
本篇来分析函数调用的过程: 通过下面一个简单的例子来进入话题: #include<stdio.h> int sum(int a,int b) { int tmp=0; tmp=a+b; return tmp; } int main() { int a=10; int b=20; int ret=0; ret=sum(a,b); printf("ret=%d\n",ret); return 0; } 首先,先从main函数开始,查看main()函数的反汇编代码,进去之后会发现在一开始就看到如下部分: 那这一部分是干什么的呢?先留个疑问,等会解决! 紧接着,继续看反汇编,如下图 画出在栈中的整个过程: 呃,画图的确有点麻烦,不过越画越清楚,^O^ 整个函数的调用,结合上面两张图就基本明白了。那现在说一下刚开始的问题,在第一张图中也做了一点标注。对于每个函数的刚开始都会出现基本类似的指令。这一大堆指令总结起来就干了四件事情: 第一:将调用方的栈底地址入栈。====》push ebp 第二:让原本指向调用方栈底的ebp指向当前函数的栈底。====》mov ebp,esp 第三:给当前函数开辟栈帧。====>sub esp,44h 第四:对开辟的栈帧进行初始化。初始化的大小不一定。====>rep stos 所以对于sum函数我们可以理解,但是在main函数刚开始也有这些指令,不由地

java 性能问题排查与性能优化

帅比萌擦擦* 提交于 2019-12-14 13:39:56
1. 代码相关 遇到性能问题,首先应该做的是检查否与业务代码相关——不是通过阅读代码解决问题,而是通过日志或代码,排除掉一些与业务代码相关的低级错误。 性能优化的最佳位置,是应用内部。 譬如,查看业务日志,检查日志内容里是否有大量的报错产生,应用层、框架层的一些性能问题,大多数都能从日志里找到端倪(日志级别设置不合理,导致线上疯狂打日志);再者,检查代码的主要逻辑,如 for 循环的不合理使用、NPE、正则表达式、数学计算等常见的一些问题,都可以通过简单地修改代码修复问题。 **别动辄就把性能优化和缓存、异步化、JVM 调优等名词挂钩,复杂问题可能会有简单解,「二八原则」在性能优化的领域里里依然有效。**当然了,了解一些基本的「代码常用踩坑点」,可以加速我们问题分析思路的过程,从 CPU、内存、JVM 等分析到的一些瓶颈点优化思路,也有可能在代码这里体现出来。 下面是一些高频的,容易造成性能问题的编码要点。 1)正则表达式非常消耗 CPU(如贪婪模式可能会引起回溯),慎用字符串的 split()、replaceAll() 等方法;正则表达式表达式一定预编译。 2)String.intern() 在低版本(Java 1.6 以及之前)的 JDK 上使用,可能会造成方法区(永久代)内存溢出。在高版本 JDK 中,如果 string pool 设置太小而缓存的字符串过多

堆栈区别

房东的猫 提交于 2019-12-13 15:19:51
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 栈和队列的区别: 栈的插入和删除操作都是在一端进行的,而队列的操作却是在两端进行的。 栈是先进后出,队列是先进先出。 栈只允许在表尾一端进行插入和删除,队列只允许在表尾一端进行插入,在表头一端进行删除。 栈和堆的区别: 栈区:由编辑器自动分配释放,存放函数的参数值,局部变量的值等(基本类型值)。 堆区:由程序员分配释放,若程序员不释放,程序结束时可能有OS回收(引用类型值)。 栈(数据结构):一种先进后出的数据结构。 堆(数据结构):堆可以被看成是一棵树,如:堆排序。 来源: oschina 链接: https://my.oschina.net/hongjiang/blog/3142648

C/C++中函数调用规则(约定)__cdecl __stdcall __thiscall __vectorcall __fastcall

混江龙づ霸主 提交于 2019-12-12 14:04:50
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 相关文献 __stdcall https://msdn.microsoft.com/en-us/library/zxk0tw93.aspx C语言函数可变参数详解 - ranpanf的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/ranpanf/article/details/4693130 关于c++变长参数列表总结 - zray4u的个人空间 -自己转载的另一篇文章 http://my.oschina.net/ray1421/blog/699538 注意平时我们所说的参数传递顺序和参数入栈顺序是一回事。 函数调用时, 调用者首先把参数压入堆栈 ,然后调用子程序,在完成后,由于堆栈中先前压入的数不再有用,调用者或者被调用者必须有一方把堆栈指针恢复到调用前的状态。参数是最右边的先入堆栈还是最左边的先入堆栈、还有由调用者还是被调用者来修正堆栈都必须有个约定,不然就会产生不正确的结果。 https://yq.aliyun.com/articles/34353 _cdecl 这个名字起的难道是 C default calling的意思 __cdecl is the default calling convention(默认的调用约定) for C and C++ programs

函数的调用规则(__cdecl,__stdcall,__fastcall,__pascal)

▼魔方 西西 提交于 2019-12-12 13:47:22
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 关于函数的调用规则(调用约定),大多数时候是不需要了解的,但是如果需要跨语言的编程,比如VC写的dll要delphi调用,则需要了解。 microsoft的vc默认的是__cdecl方式,而windows API则是__stdcall ,如果用vc开发 dll给其他语言用,则应该指定__stdcall方式 。堆栈由谁清除这个很重要,如果是要写汇编函数给C调用,一定要小心堆栈的清除工作, 如果是__cdecl方式的函数,则 函数本身 (如果不用汇编写)则 不需要关心 保存参数的 堆栈 的清除 ,但是如果是 __stdcall的规则,一定要在 函数 退出(ret)前恢复堆栈 。 1.__cdecl 所谓的C调用规则。按从右至左的顺序压参数入栈,由调用者把参数弹出栈。切记:对于传送参数的内存栈是 由调用者 来维护的。 返回值在EAX中 因此,对于象printf这样变参数的函数必须用这种规则。编译器在编译的时候对这种调用规则的函数生成修饰名的饿时候,仅在输出函数名前加上一个下划线前缀,格式为 _ functionname。 2.__stdcall 按从 右至左的顺序压参数入栈,由被调用者把参数弹出栈 。_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,切记: 函数 自己在退出时清空堆栈

LeetCode——堆栈算法题

十年热恋 提交于 2019-12-11 21:03:38
LeetCode——堆栈算法题 堆 栈 Easy 155.Min stack 20. Valid Parentheses Medium 22. Generate Parentheses 堆 栈 Easy 155.Min stack 我的代码: 用的标准的数组表示的栈结构。 class MinStack { private int N ; private int [ ] arr ; /** initialize your data structure here. */ public MinStack ( ) { N = 0 ; arr = new int [ 1 ] ; } public void push ( int x ) { if ( N == arr . length ) resize ( 2 * arr . length ) ; arr [ N ++ ] = x ; } public void pop ( ) { if ( isEmpty ( ) ) return ; //注意这边是return;不是return null N -- ; if ( N == arr . length / 4 ) resize ( arr . length / 2 ) ; } public int top ( ) { return arr [ N - 1 ] ; } public int

win32窗口程序分析

蓝咒 提交于 2019-12-11 12:39:42
1.分析消息的附加参数 例如:为了查看程序处理了哪些消息 在回调函数中调用输出函数,在控制台中输出消息的值; 结果:可以看到处理了消息7f、88、31f等消息 例如分析7f消息; 在vc6中可以选中任意一个消息类型宏,按F12进入宏的定义头文件中; 在头文件中找到7f对应的消息宏; 可以看到是WM_GETICON 在msdn中搜索WM_GETICON: 可以查msdn来分析消息的参数; 例如:分析WM_CREATE消息 通过查msdn文档可以看到该消息的wParam没使用,lParam是一个指向CREATESTRUCT结构的指针; 然后分析这个结构,将lparam强转为CREATESTRUCT*型,然后就可以获取到消息带的参数; 2.win32程序入口识别 1)入口函数WinMain int CALLBACK WinMain( //CALLBACK表示__stdcall HINSTANCE hInstance, //相当于imagebase HINSTANCE hPrevInstance, //永远都是NULL不用管 LPSTR lpCmdLine, //命令行启动程序时后面接的参数用这个来读 int nCmdShow //以什么方式显示:最大化、最小化、隐藏 ){ //... } WinMain有4个参数,并且是内平栈; 内平栈的压栈顺序是从右到左