C++最难的地方就在于指针和内存管理
内存相关
基础
C++内存分为 堆、栈和静态存储区 三个区,上面的对象可称为堆对象,栈对象,静态对象。
在C++中,所有堆对象的创建和销毁都要由程序员负责,所以,如果处理不好,就会发生内存问题。
堆对象:C++创建堆对象的唯一的方法就是用new或者 malloc ,只要使用new,就会在堆中分配一块内存,并且返回指向该堆对象的指针。
静态对象:所有的静态对象、全局对象都在静态存储区分配。一般的静态对象,程序开始时创建,结束时销毁,class的静态成员,随着第一个class object的创建时产生,在整个程序结束时销毁。
栈:前面两者之外创建的对象,就是栈对象,主要是在方法中(包括返回值 参数)创建的对象和对象内部成员。
内存释放
内存释放一定是 new 和 delete成对使用的,delete只能delete指向new且没有delete过的指针,或者空指针,其它都不行,记住这句话,记住成对,一定严格遵守,不然就会出很多错误
delete指向其它任何位置的指针都会导致严重问题。包括指向已经delete过的new的指针,通过其它任何方式得到的指针,对象取址,指针运算等。
由此
delete之后的指针一定要赋值为空
一个例子,Android项目中jni代码中创建的一个指针,然后通过取值赋值,后面给delete了。结果导致一个莫名其妙的崩溃,报错显示在glide queue线程上,Bitmap_destruce, BitmapWrap啥啥啥的,找了半天错,才发现是这个。
因为方法中 取址 赋值给这个指针,最后内存分配给glide了,然后delete,glide的线程就直接挂了。
malloc和free同理
不要在方法中创建大的对象,数组!不要在方法中创建大的对象,数组
会导致栈溢出
比如 jfloat fill[5000];
关于对象和应用
C++里面很多地方用的是对象不是引用,这点要和Java区分开
比如参数和返回值传递的时候,如果不声明引用,就是复制对象然后进行传递
容器,比如vector,放入和取出的时候,也是赋值对象而不是引用。
构造函数,编译器和自动生成拷贝构造函数。
jni函数相关
对数组元素进行操作
第一步 env.newXXXArray(len)
第二步
GetXXXArrayElements函数集,参数表示是否拷贝一份副本出来使用,返回数组指针
然后就像c++的数组指针一样操作即可
第三步 Releasexx(数组对象, 数组对象指针,mode)
这个mode和前面的get相对应,get的时候拷贝了副本,这里指定是否将缓存更新到原始数组,是否清空缓存等
0 表示更新并清空
崩溃分析:
linux的崩溃机制
.程序奔溃
在Unix-like系统中,所有的崩溃都是编程错误或者硬件错误相关的,系统遇到不可恢复的错误时会触发崩溃机制让程序退出,如除零、段地址错误等。异常发生时,CPU通过异常中断的方式,触发异常处理流程。不同的处理器,有不同的异常中断类型和中断处理方式。
linux把这些崩溃中断处理,统一为信号量,可以注册信号量向量进行处理。
三、常见崩溃类型及原因
1、SIGSEGV 段错误
SEGV_MAPERR 要访问的地址没有映射到内存空间。 比如上面对空指针的写操作, 当指针被意外复写为一个较小的数值时。
SEGV_ACCERR 访问的地址没有权限。比如试图对代码段进行写操作。
2、SIGFPE 浮点错误,一般发生在算术运行出错时。
FPE_INTDIV 除以0
FPE_INTOVE 整数溢出
3、SIGBUS 总线错误
BUS_ADRALN 地址对齐出错。arm cpu比x86 cpu 要求更严格的对齐机制,所以在 arm cpu 机器中比较常见。
4、SIGILL 发生这种错误一般是由于某处内存被意外改写了。
ILL_ILLOPC 非法的指令操作码
ILL_ILLOPN 非法的指令操作数