调用函数时,尽量用“引用传递”作为参数, 而不是直接把矩阵本身作为参数传进去,这样在内存中只有一个 P 和 Q的拷贝。
另外,看得出,这两个矩阵光存一份就已经很大了。如果连把它们读入到内存里都没办法的话,就最好考虑给自己的机器加内存条了。
不增加内存,那么降低存储空间的需求,就得增加时间复杂度。你可以把矩阵存储在多个硬盘文件里,这样每次读一部分到内存然后处理一些,存回去。最后再一点点拼出来最后结果。
中间少了一个 }
从char pe[256]; 到ifpe(pe); 看起来都没有给pe赋值啊,
那么fp=fopen(p,"rb");应该就会出错
我发现有的文件夹是无法访问的,一到那里就出错,
我从d:盘开始遍历就会找到很多文件然后再出错
而那个文件夹是用来防Auto盘符病毒的,估计可以阻止遍历,
我只能帮你到这里了,代码没发现有啥错。看你是否也有不能访问的文件夹
还有 fp 用了以后要关闭文件
APP的优化是任重而道远的过程,必须在意每一个环节,否者当你想要优化的时候,发现到处都是坑,已经不知道填补哪里了,所以我们必须一点一滴的做起。
数据结构和算法优化
能带来什么好处呢?他能使得你程序获得数据更快,内存占用更合理。最终体现为响应快内存占用小。
我们先看常见的数据结构类型特点
数组 : 一片物理上连续的大小确定的储存空间 。int[num]
顺序表 :物理上连续、逻辑上连续、大小可以动态增加。ArrayList (查找快,添加删除慢)
链表 :物理上不连续、逻辑上连续、可以动态增加和删除节点。LinkedList (查找慢只能轮寻,增加删除快)
物理上连续:数组或者链表在初始化的时候,会申请分配内存空间:只要存储空间足够你申请的大小就分配给你初始化(物理不连续);必须要连续的存储空间,我才给你分配,否则失败(物理上连续)
那么有没有继承纯虚标和链表的2个有点的数据结构呢?HashMap!
HashMap
它是由数组和链表结合组成。(HashMap:JDK17之前 24 之前: 数组+ 链表; HashMap:JDK18 之后: 数组+ 链表 + 红黑树)
下面是HashMap结构图
它是怎么 *** 作的呢?为什么他能同时拥有顺序表和链表的优点呢? 搞清它的实现方式,我们就可以知道了, 大致可以分为以下的步骤。
①put方法,传入object和value,通过hash运算得到一个int类型的hashcode,这里假设为X(后续X为这个hashcode)。
②hashmap内部是有一个table数组+链表形成的。我们拿到这个X后,使用X/tablelength(hashcode值/table[]length),得到一个小于tablelength的值M,该值就是这个value应该放置的数组位置。我们准备把value放入table[M]中。
③我们把hashcode和value打包为一个node节点(为什么需要这么打包后续会提到),准备存入table[M]中。
④出入table数组的链表中有2种方式:
前插方式:不管数组table[M]节点有值与否,都把这个准备插入的node节点作为数组的根节点。可能出现2种情况:
(1)如果table[M]节点没有值,则node节点作为数组的根节点。
(2)如果table[M]节点已存在数据链表,就把这些数据链表,链到这个准备插入的node节点上,以弄得节点为根节点放入table[M中]。
后插方式:可能会出现的2种情况
(1) 如果table[M]节点没有值,则node节点作为数组的根节点。
(2)如果table[M]节点已存在数据链表,则把node节点链到该数据链表的最后一个节点上。
经历以上4个步骤就完成了hashmap的插入 *** 作,现在解释一下为什么要打包为node节点。
举个栗子,假如hashmaplength=16,我们准备存入ObjectA(OA)和ObjectB(OB),假设OA经过hash运算得到的hashcode是1,OB经过hash运算得到hashcode是17,OA和OB进行求模运算结果都为1,链到链表上时,我们get方法的时候怎么取到正确的值呢,因为链表上的模运算都是1这个时候我们就需要通过hashcode来识别这个链表上的哪个值是OA的value哪个是OB的value,因为我们已经把hashcode和value打包起来了。
补充
hashmap的table数组的大小事是2的次幂(不要问为什么,源码定的,他们肯定经过大量的统计或者运算,这是科学)。table数组默认的长度是16,也就是说你new一个空的hashmap长度为16,当然也提供了一个给你设置长度的方法,但是假如你设置17,则长度会为32,这不难理解。
hash碰撞
hash碰撞就是,假如OA、OBON经过模运算得到的数组位置相同,那么他们都会挂在这个数组节点的链表上,极端情况想整个hashmap看起来像单链表。但这种情况这并不是我们想要的结果。我们可以通过扩容来尽可能的避免hash碰撞。
扩容 :(意义,在于避免大量的hash碰撞,因为在某些极端情况下,有点像单链表)
阈值 :阈值=tablelength DEFAULT_LOAD_FACTOR (扩容系数,默认为075,也可以自己设定,一般不做修改)
hashmap定义:当hashmap中的元素个数超过阈值大小时,我们就需要对table数组进行2倍扩容,如从16→32。
注意:扩容后hashmap会调用resize(),对hashmap内的数据重新计算所有元素的位置 。 。因为假如你之前17/16=1,现在17/32=17,你的位置发生变化了。
缺点 :
hashMap因为有阈值的扩容机制,所以一定会有空间浪费,比如075的时候,一定有25%空间被浪费掉了。空间换时间。
hashmap是线程不安全的。因为可能在一个线程扩容(resize()方法执行)的情况下,另外一个线程在get,但是拿不到之前的数据了,因为扩容。所以是线程不安全的。或者线程扩容(resize()方法执行时,多线程进行put的时候导致的多线程数据不一致。
如何线程安全的使用HashMap使用使用锁分段技术或者使用HashTable(Hashtable的方法是Synchronize的,而HashMap不是,其实也就是锁机制起作用)。
SparseArray(Android为了优化内存所提供的api)
特性:key为int,value为object,二分查找的思想,双数组,删除的时候节点不删除,而是把value删除,避免删除的时候数组还要移动。
SparseArray比HashMap更省内存,在某些条件下性能更好,主要是因为它避免了对key的自动装箱(int转为Integer类型),它内部则是通过两个数组来进行数据存储的,一个存储key,另外一个存储value,为了优化性能,它内部对数据还采取了压缩的方式来表示稀疏数组的数据,从而节约内存空间,我们从源码中可以看到key和value分别是用数组表示。
为什么是能够进行二分查找呢?从源码上看key和value分别是用int类型数组和object数组表示,所以这也是SparseArray的局限性。
private int[] mKeys;
private Object[] mValues;
为什么说SparseArray比HashMap更省内存,在某些条件下性能更好?
因为SparseArray有以下一个特性,首先它是2个数组,在数据查找的时候无疑会比hashmap快很多,其次在删除的时候,SparseArray并不会把数组key位置进行删除,而是把key的索引value置位DELETE标志(这样就避免了数组delete *** 作后的arraycopy的 *** 作)。当我们下次进行插入的时候,若要插入的位置key的索引value为DELETE标志,则把数据覆盖给value(只是经历了set *** 作,并无其他 *** 作)。否则进行add *** 作(包含arraycopy)。
所以经过以上的情况,我们可以看出,SparseArray相对于HashMap,会越用越快。
缺点
(1)SparseArray仅仅能存储key为int类型的数据。
(2)插入 *** 作需要复制数组,增删效率降低 数据量巨大时,复制数组成本巨大,gc()成本也巨大。
(3)数据量巨大时,查询效率也会明显下降。
(4)线程不安全问题,类似hashmap
一般我们在满足下面两个条件我们可以使用SparseArray代替HashMap:
(1)数据量不大,最好在千级以内
(2)key必须为int类型,这中情况下的HashMap可以用SparseArray代替:
ArrayMap(Android为了优化内存所提供的api)
ArrayMap和SparseArray差不多,不同的是key类型可以是object类型。
ArrayMap的2个数组,一个数组记录key的hash值,另外一个数组记录Value值。其他存储方式和运行思想和SparseArray一致。
线程不安全:hashmap、ArrayMap、SparseArray
个人理解:
1)说的是程序是要供人去读,去维护,因此不能为了效率牺牲这方面的性能,导致程序难以理解,维护。那样,正确性,可靠性及健壮性就无从谈起了。
2) 是说要首先着眼于全局的优化,譬如路径是否合理,有没有多余的步骤,有没有多余的循环?
3) 找出瓶颈的意思是说,程序可能由若干步骤、若干部分组成。有可能大多数步骤的效率都是100,个别步骤的是10,你应该先优化效率低的这些地方。
4) 数据结构与实际要描述的对象,你要进行合理的优化,去除不必要的冗余,等等。而算法的优化,你可以看一个在一列排好序的数列中查找一个给定数的算法,一般讲算法的书上。采用不同的算法效率是大不一样的,这比仅仅优化代码的效果要好得多。
5) 效率分为(存储)空间效率和时间效率,这两者一般比较难以统一,往往要在两者之间权衡。不过随着计算机技术的发展,现在一般计算机都可以提供足够的空间,因此空间效率往往已经不成为问题了。你只要专注于提高时间效率就可以了!
6) 紧凑的代码主要是去除了好多必要的格式字符达成的。实际执行的机器码都是经过编译产生的,而编译过程中机器会自动过滤掉格式字符,因此是否去除格式字符对编译产生的机器码没有什么影响。
以上就是关于C++ 编译程序内存过大全部的内容,包括:C++ 编译程序内存过大、用C\C++语言如何优化递归全盘遍历文件算法以不至于栈内存耗尽呢、数据结构和算法优化等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)