在最近做的工程中发现加载的图片太多或图片过大时经常出现OOM问题,找网上资料也提供了很多方法,但自己感觉有点乱,特此,今天在不同型号的三款安卓手机上做了测试,因为有效果也有结果,今天小马就做个详细的总结,以供朋友们共同交流学习,也供自己以后在解决OOM问题上有所提高,提前讲下,片幅有点长,涉及的东西太多,大家耐心看,肯定有收获的,里面的很多东西小马也是学习参考网络资料使用的,先来简单讲下下:

一般我们大家在遇到内存问题的时候常用的方式网上也有相关资料,大体如下几种:

一:在内存引用上做些处理,常用的有软引用、强化引用、弱引用

二:在内存中加载图片时直接在内存中做处理,如:边界压缩

三:动态回收内存

四:优化Dalvik虚拟机的堆内存分配

五:自定义堆内存大小

可是真的有这么简单吗,就用以上方式就能解决OOM了?不是的,继续来看...

下面小马就照着上面的次序来整理下解决的几种方式,数字序号与上面对应:

1:软引用(SoftReference)、虚引用(PhantomRefrence)、弱引用(WeakReference),这三个类是对heap中java对象的应用,通过这个三个类可以和gc做简单的交互,除了这三个以外还有一个是最常用的强引用

1.1:强引用,例如下面代码:

  1. Object o=new Object();
  2. Object o1=o;

上面代码中第一句是在heap堆中创建新的Object对象通过o引用这个对象,第二句是通过o建立o1到new Object()这个heap堆中的对象的引用,这两个引用都是强引用.只要存在对heap中对象的引用,gc就不会收集该对象.如果通过如下代码:

  1. o=null;
  2. o1=null

heap中对象有强可及对象、软可及对象、弱可及对象、虚可及对象和不可到达对象。应用的强弱顺序是强、软、弱、和虚。对于对象是属于哪种可及的对象,由他的最强的引用决定。如下:

  1. String abc=new String("abc");  //1
  2. SoftReference<String> abcSoftRef=new SoftReference<String>(abc);  //2
  3. WeakReference<String> abcWeakRef = new WeakReference<String>(abc); //3
  4. abc=null; //4
  5. abcSoftRef.clear();//5

上面的代码中:

第一行在heap对中创建内容为“abc”的对象,并建立abc到该对象的强引用,该对象是强可及的。第二行和第三行分别建立对heap中对象的软引用和弱引用,此时heap中的对象仍是强可及的。第四行之后heap中对象不再是强可及的,变成软可及的。同样第五行执行之后变成弱可及的。

1.2:软引用

软引用是主要用于内存敏感的高速缓存。在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避免内存溢出。什么时候会被收集取决于gc的算法和gc运行时可用内存的大小。当gc决定要收集软引用是执行以下过程,以上面的abcSoftRef为例:

1 首先将abcSoftRef的referent设置为null,不再引用heap中的new String("abc")对象。

2 将heap中的new String("abc")对象设置为可结束的(finalizable)。

3 当heap中的new String("abc")对象的finalize()方法被运行而且该对象占用的内存被释放, abcSoftRef被添加到它的ReferenceQueue中。

注:对ReferenceQueue软引用和弱引用可以有可无,但是虚引用必须有,参见:

  1. Reference(T paramT, ReferenceQueue<? super T>paramReferenceQueue)

被 Soft Reference 指到的对象,即使没有任何 Direct Reference,也不会被清除。一直要到 JVM 内存不足且 没有 Direct Reference 时才会清除,SoftReference 是用来设计 object-cache 之用的。如此一来 SoftReference 不但可以把对象 cache 起来,也不会造成内存不足的错误 (OutOfMemoryError)。我觉得 Soft Reference 也适合拿来实作 pooling 的技巧。

  1. A obj = new A();
  2. Refenrence sr = new SoftReference(obj);
  3. //引用时
  4. if(sr!=null){
  5. obj = sr.get();
  6. }else{
  7. obj = new A();
  8. sr = new SoftReference(obj);
  9. }

1.3:弱引用

当gc碰到弱可及对象,并释放abcWeakRef的引用,收集该对象。但是gc可能需要对此运用才能找到该弱可及对象。通过如下代码可以了明了的看出它的作用:

  1. String abc=new String("abc");
  2. WeakReference<String> abcWeakRef = new WeakReference<String>(abc);
  3. abc=null;
  4. System.out.println("before gc: "+abcWeakRef.get());
  5. System.gc();
  6. System.out.println("after gc: "+abcWeakRef.get());

运行结果:

before gc: abc

after gc: null

gc收集弱可及对象的执行过程和软可及一样,只是gc不会根据内存情况来决定是不是收集该对象。如果你希望能随时取得某对象的信息,但又不想影响此对象的垃圾收集,那么你应该用 Weak Reference 来记住此对象,而不是用一般的 reference。

  1. A obj = new A();
  2. WeakReference wr = new WeakReference(obj);
  3. obj = null;
  4. //等待一段时间,obj对象就会被垃圾回收
  5.   ...
  6.   if (wr.get()==null) {
  7.   System.out.println("obj 已经被清除了 ");
  8.   } else {
  9.   System.out.println("obj 尚未被清除,其信息是 "+obj.toString());
  10.   }
  11.   ...
  12. }

在此例中,透过 get() 可以取得此 Reference 的所指到的对象,如果返回值为 null 的话,代表此对象已经被清除。这类的技巧,在设计 Optimizer 或 Debugger 这类的程序时常会用到,因为这类程序需要取得某对象的信息,但是不可以 影响此对象的垃圾收集。

1.4:虚引用

就是没有的意思,建立虚引用之后通过get方法返回结果始终为null,通过源代码你会发现,虚引用通向会把引用的对象写进referent,只是get方法返回结果为null.先看一下和gc交互的过程在说一下他的作用.

1.4.1 不把referent设置为null, 直接把heap中的new String("abc")对象设置为可结束的(finalizable).

1.4.2 与软引用和弱引用不同, 先把PhantomRefrence对象添加到它的ReferenceQueue中.然后在释放虚可及的对象.

你会发现在收集heap中的new String("abc")对象之前,你就可以做一些其他的事情.通过以下代码可以了解他的作用.

  1. import java.lang.ref.PhantomReference;
  2. import java.lang.ref.Reference;
  3. import java.lang.ref.ReferenceQueue;
  4. import java.lang.reflect.Field;
  5. public class Test {
  6. public static boolean isRun = true;
  7. public static void main(String[] args) throws Exception {
  8. String abc = new String("abc");
  9. System.out.println(abc.getClass() + "@" + abc.hashCode());
  10. final ReferenceQueue referenceQueue = new ReferenceQueue<String>();
  11. new Thread() {
  12. public void run() {
  13. while (isRun) {
  14. Object o = referenceQueue.poll();
  15. if (o != null) {
  16. try {
  17. Field rereferent = Reference.class
  18. .getDeclaredField("referent");
  19. rereferent.setAccessible(true);
  20. Object result = rereferent.get(o);
  21. System.out.println("gc will collect:"
  22. + result.getClass() + "@"
  23. + result.hashCode());
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }
  29. }
  30. }.start();
  31. PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,
  32. referenceQueue);
  33. abc = null;
  34. Thread.currentThread().sleep(3000);
  35. System.gc();
  36. Thread.currentThread().sleep(3000);
  37. isRun = false;
  38. }
  39. }

结果为

class java.lang.String@96354

gc will collect:class java.lang.String@96354  好了,关于引用就讲到这,下面看2

2:在内存中压缩小马做了下测试,对于少量不太大的图片这种方式可行,但太多而又大的图片小马用个笨的方式就是,先在内存中压缩,再用软引用避免OOM,两种方式代码如下,大家可参考下:

方式一代码如下:

  1. @SuppressWarnings("unused")
  2. private Bitmap copressImage(String imgPath){
  3. File picture = new File(imgPath);
  4. Options bitmapFactoryOptions = new BitmapFactory.Options();
  5. //下面这个设置是将图片边界不可调节变为可调节
  6. bitmapFactoryOptions.inJustDecodeBounds = true;
  7. bitmapFactoryOptions.inSampleSize = 2;
  8. int outWidth  = bitmapFactoryOptions.outWidth;
  9. int outHeight = bitmapFactoryOptions.outHeight;
  10. bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),
  11. bitmapFactoryOptions);
  12. float imagew = 150;
  13. float imageh = 150;
  14. int yRatio = (int) Math.ceil(bitmapFactoryOptions.outHeight
  15. / imageh);
  16. int xRatio = (int) Math
  17. .ceil(bitmapFactoryOptions.outWidth / imagew);
  18. if (yRatio > 1 || xRatio > 1) {
  19. if (yRatio > xRatio) {
  20. bitmapFactoryOptions.inSampleSize = yRatio;
  21. } else {
  22. bitmapFactoryOptions.inSampleSize = xRatio;
  23. }
  24. }
  25. bitmapFactoryOptions.inJustDecodeBounds = false;
  26. bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),
  27. bitmapFactoryOptions);
  28. if(bmap != null){
  29. //ivwCouponImage.setImageBitmap(bmap);
  30. return bmap;
  31. }
  32. return null;
  33. }

方式二代码如下:

  1. package com.lvguo.scanstreet.activity;
  2. import java.io.File;
  3. import java.lang.ref.SoftReference;
  4. import java.util.ArrayList;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import android.app.Activity;
  8. import android.app.AlertDialog;
  9. import android.content.Context;
  10. import android.content.DialogInterface;
  11. import android.content.Intent;
  12. import android.content.res.TypedArray;
  13. import android.graphics.Bitmap;
  14. import android.graphics.BitmapFactory;
  15. import android.graphics.BitmapFactory.Options;
  16. import android.os.Bundle;
  17. import android.view.View;
  18. import android.view.ViewGroup;
  19. import android.view.WindowManager;
  20. import android.widget.AdapterView;
  21. import android.widget.AdapterView.OnItemLongClickListener;
  22. import android.widget.BaseAdapter;
  23. import android.widget.Gallery;
  24. import android.widget.ImageView;
  25. import android.widget.Toast;
  26. import com.lvguo.scanstreet.R;
  27. import com.lvguo.scanstreet.data.ApplicationData;
  28. /**
  29. * @Title: PhotoScanActivity.java
  30. * @Description: 照片预览控制类
  31. * @author XiaoMa
  32. */
  33. public class PhotoScanActivity extends Activity {
  34. private Gallery gallery ;
  35. private List<String> ImageList;
  36. private List<String> it ;
  37. private ImageAdapter adapter ;
  38. private String path ;
  39. private String shopType;
  40. private HashMap<String, SoftReference<Bitmap>> imageCache = null;
  41. private Bitmap bitmap = null;
  42. private SoftReference<Bitmap> srf = null;
  43. @Override
  44. public void onCreate(Bundle savedInstanceState) {
  45. super.onCreate(savedInstanceState);
  46. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  47. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  48. setContentView(R.layout.photoscan);
  49. Intent intent = this.getIntent();
  50. if(intent != null){
  51. if(intent.getBundleExtra("bundle") != null){
  52. Bundle bundle = intent.getBundleExtra("bundle");
  53. path = bundle.getString("path");
  54. shopType = bundle.getString("shopType");
  55. }
  56. }
  57. init();
  58. }
  59. private void init(){
  60. imageCache = new HashMap<String, SoftReference<Bitmap>>();
  61. gallery = (Gallery)findViewById(R.id.gallery);
  62. ImageList = getSD();
  63. if(ImageList.size() == 0){
  64. Toast.makeText(getApplicationContext(), "无照片,请返回拍照后再使用预览", Toast.LENGTH_SHORT).show();
  65. return ;
  66. }
  67. adapter = new ImageAdapter(this, ImageList);
  68. gallery.setAdapter(adapter);
  69. gallery.setOnItemLongClickListener(longlistener);
  70. }
  71. /**
  72. * Gallery长按事件操作实现
  73. */
  74. private OnItemLongClickListener longlistener = new OnItemLongClickListener() {
  75. @Override
  76. public boolean onItemLongClick(AdapterView<?> parent, View view,
  77. final int position, long id) {
  78. //此处添加长按事件删除照片实现
  79. AlertDialog.Builder dialog = new AlertDialog.Builder(PhotoScanActivity.this);
  80. dialog.setIcon(R.drawable.warn);
  81. dialog.setTitle("删除提示");
  82. dialog.setMessage("你确定要删除这张照片吗?");
  83. dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {
  84. @Override
  85. public void onClick(DialogInterface dialog, int which) {
  86. File file = new File(it.get(position));
  87. boolean isSuccess;
  88. if(file.exists()){
  89. isSuccess = file.delete();
  90. if(isSuccess){
  91. ImageList.remove(position);
  92. adapter.notifyDataSetChanged();
  93. //gallery.setAdapter(adapter);
  94. if(ImageList.size() == 0){
  95. Toast.makeText(getApplicationContext(), getResources().getString(R.string.phoSizeZero), Toast.LENGTH_SHORT).show();
  96. }
  97. Toast.makeText(getApplicationContext(), getResources().getString(R.string.phoDelSuccess), Toast.LENGTH_SHORT).show();
  98. }
  99. }
  100. }
  101. });
  102. dialog.setNegativeButton("取消",new DialogInterface.OnClickListener() {
  103. @Override
  104. public void onClick(DialogInterface dialog, int which) {
  105. dialog.dismiss();
  106. }
  107. });
  108. dialog.create().show();
  109. return false;
  110. }
  111. };
  112. /**
  113. * 获取SD卡上的所有图片文件
  114. * @return
  115. */
  116. private List<String> getSD() {
  117. /* 设定目前所在路径 */
  118. File fileK ;
  119. it = new ArrayList<String>();
  120. if("newadd".equals(shopType)){
  121. //如果是从查看本人新增列表项或商户列表项进来时
  122. fileK = new File(ApplicationData.TEMP);
  123. }else{
  124. //此时为纯粹新增
  125. fileK = new File(path);
  126. }
  127. File[] files = fileK.listFiles();
  128. if(files != null && files.length>0){
  129. for(File f : files ){
  130. if(getImageFile(f.getName())){
  131. it.add(f.getPath());
  132. Options bitmapFactoryOptions = new BitmapFactory.Options();
  133. //下面这个设置是将图片边界不可调节变为可调节
  134. bitmapFactoryOptions.inJustDecodeBounds = true;
  135. bitmapFactoryOptions.inSampleSize = 5;
  136. int outWidth  = bitmapFactoryOptions.outWidth;
  137. int outHeight = bitmapFactoryOptions.outHeight;
  138. float imagew = 150;
  139. float imageh = 150;
  140. int yRatio = (int) Math.ceil(bitmapFactoryOptions.outHeight
  141. / imageh);
  142. int xRatio = (int) Math
  143. .ceil(bitmapFactoryOptions.outWidth / imagew);
  144. if (yRatio > 1 || xRatio > 1) {
  145. if (yRatio > xRatio) {
  146. bitmapFactoryOptions.inSampleSize = yRatio;
  147. } else {
  148. bitmapFactoryOptions.inSampleSize = xRatio;
  149. }
  150. }
  151. bitmapFactoryOptions.inJustDecodeBounds = false;
  152. bitmap = BitmapFactory.decodeFile(f.getPath(),
  153. bitmapFactoryOptions);
  154. //bitmap = BitmapFactory.decodeFile(f.getPath());
  155. srf = new SoftReference<Bitmap>(bitmap);
  156. imageCache.put(f.getName(), srf);
  157. }
  158. }
  159. }
  160. return it;
  161. }
  162. /**
  163. * 获取图片文件方法的具体实现
  164. * @param fName
  165. * @return
  166. */
  167. private boolean getImageFile(String fName) {
  168. boolean re;
  169. /* 取得扩展名 */
  170. String end = fName
  171. .substring(fName.lastIndexOf(".") + 1, fName.length())
  172. .toLowerCase();
  173. /* 按扩展名的类型决定MimeType */
  174. if (end.equals("jpg") || end.equals("gif") || end.equals("png")
  175. || end.equals("jpeg") || end.equals("bmp")) {
  176. re = true;
  177. } else {
  178. re = false;
  179. }
  180. return re;
  181. }
  182. public class ImageAdapter extends BaseAdapter{
  183. /* 声明变量 */
  184. int mGalleryItemBackground;
  185. private Context mContext;
  186. private List<String> lis;
  187. /* ImageAdapter的构造符 */
  188. public ImageAdapter(Context c, List<String> li) {
  189. mContext = c;
  190. lis = li;
  191. TypedArray a = obtainStyledAttributes(R.styleable.Gallery);
  192. mGalleryItemBackground = a.getResourceId(R.styleable.Gallery_android_galleryItemBackground, 0);
  193. a.recycle();
  194. }
  195. /* 几定要重写的方法getCount,传回图片数目 */
  196. public int getCount() {
  197. return lis.size();
  198. }
  199. /* 一定要重写的方法getItem,传回position */
  200. public Object getItem(int position) {
  201. return lis.get(position);
  202. }
  203. /* 一定要重写的方法getItemId,传并position */
  204. public long getItemId(int position) {
  205. return position;
  206. }
  207. /* 几定要重写的方法getView,传并几View对象 */
  208. public View getView(int position, View convertView, ViewGroup parent) {
  209. System.out.println("lis:"+lis);
  210. File file = new File(it.get(position));
  211. SoftReference<Bitmap> srf = imageCache.get(file.getName());
  212. Bitmap bit = srf.get();
  213. ImageView i = new ImageView(mContext);
  214. i.setImageBitmap(bit);
  215. i.setScaleType(ImageView.ScaleType.FIT_XY);
  216. i.setLayoutParams( new Gallery.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
  217. WindowManager.LayoutParams.WRAP_CONTENT));
  218. return i;
  219. }
  220. }
  221. }

上面两种方式第一种直接使用边界压缩,第二种在使用边界压缩的情况下间接的使用了软引用来避免OOM,但大家都知道,这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存,如果图片多且大,这种方式还是会引用OOM异常的,不着急,有的是办法解决,继续看,以下方式也大有妙用的:

  1. 1. InputStream is = this.getResources().openRawResource(R.drawable.pic1);
  2. BitmapFactory.Options options=new BitmapFactory.Options();
  3. options.inJustDecodeBounds = false;
  4. options.inSampleSize = 10;   //width,hight设为原来的十分一
  5. Bitmap btp =BitmapFactory.decodeStream(is,null,options);
  6. 2. if(!bmp.isRecycle() ){
  7. bmp.recycle()   //回收图片所占的内存
  8. system.gc()  //提醒系统及时回收
  9. }

上面代码与下面代码大家可分开使用,也可有效缓解内存问题哦...吼吼...

  1. /** 这个地方大家别搞混了,为了方便小马把两个贴一起了,使用的时候记得分开使用
  2. * 以最省内存的方式读取本地资源的图片
  3. */
  4. public static Bitmap readBitMap(Context context, int resId){
  5. BitmapFactory.Options opt = new BitmapFactory.Options();
  6. opt.inPreferredConfig = Bitmap.Config.RGB_565;
  7. opt.inPurgeable = true;
  8. opt.inInputShareable = true;
  9. //获取资源图片
  10. InputStream is = context.getResources().openRawResource(resId);
  11. return BitmapFactory.decodeStream(is,null,opt);
  12. }

3:大家可以选择在合适的地方使用以下代码动态并自行显式调用GC来回收内存:

  1. if(bitmapObject.isRecycled()==false) //如果没有回收
  2. bitmapObject.recycle();

4:这个就好玩了,优化Dalvik虚拟机的堆内存分配,听着很强大,来看下具体是怎么一回事

     对于Android平台来说,其托管层使用的Dalvik JavaVM从目前的表现来看还有很多地方可以优化处理,比如我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。当然具体原理我们可以参考开源工程,这里我们仅说下使用方法: 代码如下:

  1. private final static floatTARGET_HEAP_UTILIZATION = 0.75f;
  2. 在程序onCreate时就可以调用
  3. VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);
  4. 即可

5:自定义我们的应用需要多大的内存,这个好暴力哇,强行设置最小内存大小,代码如下:

  1. private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
  2. //设置最小heap内存为6MB大小
  3. VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);

好了,文章写完了,片幅有点长,因为涉及到的东西太多了,其它文章小马都会贴源码,这篇文章小马是直接在项目中用三款安卓真机测试的,有效果,项目原码就不在这贴了,不然泄密了都,吼吼,但这里讲下还是会因为手机的不同而不同,大家得根据自己需求选择合适的方式来避免OOM,大家加油呀,每天都有或多或少的收获,这也算是进步,加油加油!

本文出自 “酷_莫名简单、KNothing” 博客,请务必保留此出处http://mzh3344258.blog.51cto.com/1823534/804237

Android 内存溢出解决方案(OOM) 整理总结<转>的更多相关文章

  1. Android 内存溢出解决方案(OOM) 整理总结

    在最近做的工程中发现加载的图片太多或图片过大时经常出现OOM问题,找网上资料也提供了很多方法,但自己感觉有点乱,特此,今天在不同型号的三款安卓手机上做了测试,因为有效果也有结果,今天小马就做个详细的总 ...

  2. Android内存溢出解决方案(OOM)

    众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视平台而定).因此在开发应用时需要特别关注自身的内存使用量,而一般最耗内存量的资源,一般是图片.音频文 ...

  3. Android内存溢出解决方案总结

    我的视频会议中有三个内存泄露的崆点: 1) BNLiveControlView mView = this; 未释放 (自定义view中自己引用自己造成) 2) 在自定义View中区注册了系统的网络变化 ...

  4. Android ImageSwitcher 配合Picasso解决内存溢出(OOM)问题

    最近项目中用到了 ImageSwitcher 来实现图片切换,使用起来很简单,但发现当图片比较大(超过了3M)时,程序出现了内存溢出(OOM)问题而崩溃了. 原因就是图片太大了,显示到 ImageVi ...

  5. 1篇文章搞清楚8种JVM内存溢出(OOM)的原因和解决方法

    前言 撸Java的同学,多多少少会碰到内存溢出(OOM)的场景,但造成OOM的原因却是多种多样. 堆溢出 这种场景最为常见,报错信息: java.lang.OutOfMemoryError: Java ...

  6. Android 内存溢出处理方案

    转自 : http://www.cnblogs.com/hello-ruby/archive/2013/04/19/3031098.html 首先我们来看看android内存溢出的原因,有可能是: 由 ...

  7. 应用jacob组件造成的内存溢出解决方案(java.lang.OutOfMemoryError: Java heap space)

    http://www.educity.cn/wenda/351088.html 使用jacob组件造成的内存溢出解决方案(java.lang.OutOfMemoryError: Java heap s ...

  8. PHP内存溢出解决方案

    一.内存溢出解决方案 在做数据统计分析时,经常会遇到大数组,可能会发生内存溢出,这里分享一下我的解决方案.还是用例子来说明这个问题,如下: 假定日志中存放的记录数为500000条,那么解决方案如下: ...

  9. 【转载】Android 内存溢出如何发生的。

    [转载]Android 内存溢出如何发生的. 且谈Android内存溢出 前言 关于android的内存溢出在创新文档库中也有不少,网络上也有很多这方面的资料.所以这遍文章不算是正真意义上的创新,仅仅 ...

随机推荐

  1. 认识正则RegExp;

    1.什么是正则??? 就是一条规则,用于检验字符串的格式,目标就是字符串. *只要是表单提交的数据都是字符串 2.正则的定义??? (1)var reg=new RegExp() (2)var reg ...

  2. vi/vim 文字处理器常用命令

    目录 vi 与vim vi 的三种模式 vi 光标移动 vi 搜索与替换 vi 删除 vi 复制 vi 粘贴 vi 其他 vi 进入编辑模式 vi 命令行命令 vim 附加功能 vi 与vim vi是 ...

  3. 查看class实际执行的类路径

    查看class真实归属的jar包位置getClass().getClassLoader().getResource(getClass().getName().replace('.', '/') + & ...

  4. freeRTOS与裸机程序相比有什么区别??

    FreeRTOS命名及变量规则 初学FreeRTOS的用户对其变量和函数的命名比较迷惑,    FreeRTOS的核心源代码遵从MISRA编码标准指南,关于MISRA编码标准,可以查看文章https: ...

  5. C#顺序表 & 单向链表(无头)

    C# 顺序表 非常标准的顺序表结构,等同于C#中的List<T>,但是List<T>在排错查询和数据结构替换上存在缺陷,一些情况会考虑使用自己定义的数据结构 1.优化方向 下表 ...

  6. JDBC创建链接的几种方式

    首先,使用java程序访问数据库的前提 数据库的主机地址(ip地址) 端口 数据库用户名 数据库用户密码 连接的数据库 代码: private static String url = "jd ...

  7. 连接SSH服务器的脚本,自动发送用户名和密码

    利用expect 自动输入用户名和密码 脚本如下 #!/usr/bin/expect # connect ssh server set timeout 30 spawn ssh -l user_nam ...

  8. C#自定义异常 统一异常处理

    异常类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...

  9. CPU Hardwar

    GPU负责把线程块分配到各个SM上处理. CUDA对申请的线程块何时运行,以及在哪个SM上运行是没有保证的.这恰好是GPU的优势,这种方式带来了灵活性,不需程序根据SM的数量去配置程序. 但是一个bl ...

  10. Linux下Redis安装使用教程

    https://redis.io/download 第一步:安装redis需要在有c语言的编译环境下,执行命令安装c语言环境: yum install gcc-c++ https://blog.csd ...