Android优化指南
Android系统中GC内存泄漏的原因
主动回收内存System.gc();、getruntime.runtime.gc
导致内存泄漏主要的原因是,申请了内存空间而忘记了释放。如果程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器GC验证这些对象是否不再需要。如果存在对象的引用,这个对象就被定义为"有效的活动",同时不会被释放。要确定对象所占内存将被回收,我们就要务必确认该对象不再会被使用。典型的做法就是把对象数据成员设为null或者从集合中移除该对象。但当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理。
什么是GC
GC垃圾收集器,它让创建的对象不需要像c/c++那样delete、free掉,GC的时间系统自身决定,时间不可预测或者说调用System.gc()的时候。 对超出作用域的对象或引用置为空的对象进行清理,删除不使用的对象,腾出内存空间。
Java带垃圾回收的机制,为什么还会内存泄露呢?
举个例子 当你堆里某个对象没有被引用时,然后再过一段时间,垃圾回收机制才会回收,那么
while(true){
String str=new String("ni hao ni hao ");
}
一直循环创建 String对象。。。你觉得堆不会溢出嘛。。。
垃圾回收 要有2个条件
1 该对象没有被引用
2 过了一段时间
Java 内存泄露的根本原因就是 保存了不可能再被访问的变量类型的引用,回收不确定性
内存溢出和内存泄漏
内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。memory leak会最终会导致out of memory!
内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。
Java中有内存泄露吗?举一些例子?
1.查询数据库没有关闭游标 2. 构造Adapter时,没有使用缓存的 convertView 3. Bitmap对象不再使用时调用recycle()释放内存 4. 无用时没有释放对象的引用 5. 在Activity中使用非静态的内部类,并开启一个长时间运行的线程,因为内部类持有Activity的引用,会导致Activity本来可以被gc时却长期得不到回收 6.使用Handler处理消息前,Activity通过例如finish()退出,导致内存泄漏 7.动态注册广播在Activity销毁前没有unregisterReceive
内存的优化
- 回收已经使用的资源,比如游标cursor 、I/O、Bitmap(close并且引用置为null)
- 合理的使用缓存,比如图片是很耗内存的,使用lru缓存图片和压缩
- 合理设置变量的作用范围
- 节制的使用服务,后台任务运行完,即使它不执行任何操作,服务也会一直运行,这些是十分消耗内存的,可以用intentservice
- 当界面不可见时释放内存,在activity的onTrimMemory方法里与ui的相关资源,在onstop里释放与组件相关的资源
- 合理的使用多进程,如果后台任务和前台界面是相互独立在,可以在组件标签下写process,这样这个组建就在另一个进程里了。而服务的话更倾向于开启自己所依赖的进程,而那个进程可能很多东西都不需要,比如ui
使用线程池、对象池
Bitmap对象在不使用时,应该先调用recycle()释放内存,然后才它设置为null。
说说线程池
好处
避免线程的创建和销毁所带来的性能得开销
能有效控制线程池的最大并发数,避免了大量线程间抢占资源而导致的阻塞现象
能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能
由于不需要每次处理复杂逻辑耗时操作,比如加载网络并不需要都开启一个新的线程,可以用线程池处理,把线程存起来,用的时候在取出来,
在onDestory里去销毁线程,这样就会节省内存
//AsyncTask就是Handler和线程池的封装
//自定义线程池
public class ThreadManager {
private ThreadManager() {
}
private static ThreadManager instance = new ThreadManager();
private ThreadPoolProxy longPool;
private ThreadPoolProxy shortPool;
public static ThreadManager getInstance() {
return instance;
}
// 联网比较耗时
// 开启线程数一般是cpu的核数*2+1
public synchronized ThreadPoolProxy createLongPool() {
if (longPool == null) {
longPool = new ThreadPoolProxy(5, 5, 5000L);
}
return longPool;
}
// 操作本地文件
public synchronized ThreadPoolProxy createShortPool() {
if(shortPool==null){
shortPool = new ThreadPoolProxy(3, 3, 5000L);
}
return shortPool;
}
public class ThreadPoolProxy {
private ThreadPoolExecutor pool;
private int corePoolSize;
private int maximumPoolSize;
private long time;
public ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long time) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.time = time;
}
/**
* 执行任务
* @param runnable
*/
public void execute(Runnable runnable) {
if (pool == null) {
// 创建线程池
/*
* 1. 线程池里面管理多少个线程2. 如果排队满了, 额外的开的线程数3. 如果线程池没有要执行的任务 存活多久4.
* 时间的单位 5 如果 线程池里管理的线程都已经用了,剩下的任务 临时存到LinkedBlockingQueue对象中 排队
*/
pool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
time, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(10));
}
pool.execute(runnable); // 调用线程池 执行异步任务
}
/**
* 取消任务
* @param runnable
*/
public void cancel(Runnable runnable) {
if (pool != null && !pool.isShutdown() && !pool.isTerminated()) {
pool.remove(runnable); // 取消异步任务
}
}
}
}
静态内部类:尽量不要用一个生命周期长于Activity的对象来持有Activity的引用。声明handler为static类,这样内部类就不再持有外部类的引用了,就不会阻塞Activity的释放。在Activity中尽量避免使用生命周期不受控制的非静态类型的内部类,可以使用静态类型的内部类加上弱引用的方式实现。
静态变量:不要直接或者间接引用Activity、Service等。这会使用Activity以及它所引用的所有对象无法释放,然后,用户操作时间一长,内存就会狂升。
- 静态引用:应该避免 static 成员变量引用资源耗费过多的实例,比如 Context。尽量使用 getApplicationContext:如果为了满足需求下必须使用 Context 的话:Context 尽量使用 Application Context,因为 Application 的 Context 的生命周期比较长,引用它不会出现内存泄露的问题,而不是activity的context,单例。可以通过调用 Context.getApplicationContext() or Activity.getApplication()来获得
Handler内存泄漏
Handler作为内部类存在于Activity中,但是Handler生命周期与Activity生命周期往往并不是相同的,比如当Handler对象有Message在排队,则无法释放,进而导致本该释放的Acitivity也没有办法进行回收。
解决办法:声明handler为static类,这样内部类就不再持有外部类的引用了,就不会阻塞Activity的释放
System.gc()
我们可以调用System.gc方法,建议虚拟机进行垃圾回收工作(注意,是建议,但虚拟机会不会这样干,我们也无法预知!)
下面来看一个例子来了解finalize()和System.gc()的使用:
public class TestGC {
public TestGC() {} //当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
protected void finalize() {
System.out.println("我已经被垃圾回收器回收了...");
} public static void main(String [] args) {
TestGC gc = new TestGC();
gc = null;
// 建议虚拟机进行垃圾回收工作
System.gc();
}
}
如上面的例子所示,大家可以猜猜重写的finalize方法会不会执行?
答案是:不一定!
因为无论是设置gc的引用为null还是调用System.gc()方法都只是"建议"垃圾回收器进行垃圾回收,但是最终所有权还在垃圾回收器手中,它会不会进行回收我们无法预知!
AsynTask为什么要设计为只能够一次任务?
最核心的还是线程安全问题,多个子线程同时运行,会产生状态不一致的问题。所以要务必保证只能够执行一次
java中的soft reference
StrongReference 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收,SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存
内存溢出OOM解决方案?(解决方法)
内存缓存的时候可能内存溢出,因为Android默认给每个app只分配16M的内存,,每个手机不一样,我的手机是3G内存,分配的内存是29m,通过这样可以获得
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
解决方法1:java中的引用(使用软引用)
- 强引用 垃圾回收器不会回收, java默认引用都是强引用
- 软引用 SoftReference 在内存不够时,垃圾回收器会考虑回收
- 弱引用 WeakReference 在内存不够时,垃圾回收器会优先回收
- 虚引用 PhantomReference 在内存不够时,垃圾回收器最优先回收
注意: Android2.3+, 系统会优先将SoftReference的对象提前回收掉, 即使内存够用
内存中使用LRUCache是最合适的。如果用HashMap来实现,不是不可以,但需要注意在合适的时候释放缓存。至于具体怎么释放,我没考虑过,但用软引用的问题在于,你很难控制缓存的大小,也就是说,只有等到你的内存快要撑爆,你的图片缓存才会被回收。是不是感觉傻傻的?
解决方法2:LruCache
least recentlly use 最少最近使用算法
会将内存控制在一定的大小内, 超出最大值时会自动回收, 这个最大值开发者自己定。他内部是是一个linkedhashmap以强引用的方式存储外界的缓存对象,提供了get,put方法来操作,当缓存满了,lru会移除较早使用的缓存对象,把新的添加进来。也可以自己remove
解决方法3:图片压缩
三级缓存
- 先读取内存缓存, 因为优先加载, 速度最快,内存缓存没有再读取本地缓存, 次优先加载, 速度也快,本地没有再加载网络缓存, 速度慢,浪费流量在网络缓存中从网络下载图片,并且保存在本地和内存中,在下载的时候可以对图片进行压缩
- 服务器端下载的图片是使用 Http的缓存机制,每次执行将本地图片的时间发送给服务器,如果俩次访问的时间间隔短,返回码是 304,会读取网络缓存(说明服务端的图片和本地的图片是相同的,直接使用本地保存的图片),如果返回码是 200,则开始下载新的图片并实现缓存。在从服务器获取到图片后,需要再在本地和内存中分别存一份,这样下次直接就可以从内存中直接获取了,这样就加快了显示的速度,提高了用户的体验。
- 大量图片加载,当用户不停的滑动时,由于ui在主线程操作的,会出现卡顿,可以在滑动的时候停止加载(setOnscrollerListener),在getView方法里只有静止才加载图片
InputStream inputStream = conn.getInputStream(); //图片压缩处理
BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定
option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片格式 Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
return bitmap;
....
本地保存时可以将名字用MD5加密保存
// 将图片保存在本地,
bitmap.compress(CompressFormat.JPEG, 100,
new FileOutputStream(file));//100是质量
//取
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
file));//decodeStream放的是输入输出流
return bitmap; Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
file));//
return bitmap;
内存缓存在保存的时候可以给图片分配内存
private LruCache<String, Bitmap> mMemoryCache;
public MemoryCacheUtils() {
long maxMemory = Runtime.getRuntime().maxMemory() / 8;//主流都是分配16m的8/1
mMemoryCache = new LruCache<String, Bitmap>((int) maxMemory) {
@Override
protected int sizeOf(String key, Bitmap value) {
int byteCount = value.getRowBytes() * value.getHeight();// 获取图片占用内存大小
return byteCount;
}
};
}
正常一张720x1080的图片在内存中占多少空间?怎么加载大图片?
看他的渲染方式,RGB888啥的,占用的字节不同的。
如果是一张的话压缩处理,大量图片的话用lru
图片的总大小 = 图片的总像素 * 每个像素占用的大小
加载大图片
- 计算机把图片所有像素信息全部解析出来,保存至内存
Android保存图片像素信息,是用ARGB保存,所以每个像素占用4个字节,很容易内存溢出
可以对图片的宽高和质量进行压缩
首先对图片进行缩放
获取屏幕宽高
//设置缩放比例
opts.inSampleSize = scale;
//为图片申请内存
opts.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
iv.setImageBitmap(bm); int scale = 1;
int scaleX = imageWidth / screenWidth;
int scaleY = imageHeight / screenHeight;
if(scaleX >= scaleY && scaleX > 1){
scale = scaleX;
}
else if(scaleY > scaleX && scaleY > 1){
scale = scaleY;
}
Options opts = new Options();
//请求图片属性但不申请内存
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
int imageWidth = opts.outWidth;
int imageHeight = opts.outHeight;
Display dp = getWindowManager().getDefaultDisplay();
int screenWidth = dp.getWidth();
int screenHeight = dp.getHeight();获取图片宽高
//设置缩放比例
opts.inSampleSize = scale;
//为图片申请内存
opts.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
iv.setImageBitmap(bm); int scale = 1;
int scaleX = imageWidth / screenWidth;
int scaleY = imageHeight / screenHeight;
if(scaleX >= scaleY && scaleX > 1){
scale = scaleX;
}
else if(scaleY > scaleX && scaleY > 1){
scale = scaleY;
}
Options opts = new Options();
//请求图片属性但不申请内存
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
int imageWidth = opts.outWidth;
int imageHeight = opts.outHeight;图片的宽高除以屏幕宽高,算出宽和高的缩放比例,取较大值作为图片的缩放比例,且大于1才缩放
//设置缩放比例
opts.inSampleSize = scale;
//为图片申请内存
opts.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
iv.setImageBitmap(bm); int scale = 1;
int scaleX = imageWidth / screenWidth;
int scaleY = imageHeight / screenHeight;
if(scaleX >= scaleY && scaleX > 1){
scale = scaleX;
}
else if(scaleY > scaleX && scaleY > 1){
scale = scaleY;
}
2.然后按缩放比例加载图片
//设置缩放比例
opts.inSampleSize = scale;
//为图片申请内存
opts.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
iv.setImageBitmap(bm);
如何在不失真的条件下显示一张超高清的图片或者长图
针对这个问题,我自己一般用以下两种方法解决: 1、使用WebView来加载该图片; 2、使用MapView或者TileView来显示图片(类似地图的机制);
- 保持良好的编程习惯,不要重复或者不用的代码,谨慎添加libs,移除使用不到的libs。
- 使用proguard混淆代码,它会对不用的代码做优化,并且混淆后也能够减少安装包的大小。
- native code的部分,大多数情况下只需要支持armabi与x86的架构即可。如果非必须,可以考虑拿掉x86的部分。
- 使用Lint工具查找没有使用到的资源。去除不使用的图片,String,XML等等。
- assets目录下的资源请确保没有用不上的文件。
- 生成APK的时候,aapt工具本身会对png做优化,但是在此之前还可以使用其他工具如tinypng对图片进行进一步的压缩预处理。
- jpeg还是png,根据需要做选择,在某些时候jpeg可以减少图片的体积。
- 对于9.png的图片,可拉伸区域尽量切小,另外可以通过使用9.png拉伸达到大图效果的时候尽量不要使用整张大图。
- 有选择性的提供hdpi,xhdpi,xxhdpi的图片资源。建议优先提供xhdpi的图片,对于mdpi,ldpi与xxxhdpi根据需要提供有差异的部分即可。
- 尽可能的重用已有的图片资源。例如对称的图片,只需要提供一张,另外一张图片可以通过代码旋转的方式实现。
- 能用代码绘制实现的功能,尽量不要使用大量的图片。例如减少使用多张图片组成animate-list的AnimationDrawable,这种方式提供了多张图片很占空间。
ListView的优化
- 复用convertview , 历史的view对象
- 减少子孩子查询的次数 viewholder
- 异步加载数据(把图片缓存)
- 条目多时分页加载数据
加载时显示进度条让用户等待
Item的布局层次结构尽量简单,避免布局太深或者不必要的重绘
避免在 getView 方法中做耗时的操作:
例如加载本地 Image 需要载入内存以及解析 Bitmap ,都是比较耗时的操作,如果用户快速滑动listview,会因为getview逻辑过于复杂耗时而造成滑动卡顿现象。用户滑动时候不要加载图片,待滑动完成再加载,可以使用这个第三方库glide- 应该尽量避免 static 成员变量引用资源耗费过多的实例,比如 Context。
尽量使用 getApplicationContext:如果为了满足需求下必须使用 Context 的话:Context 尽量使用 Application Context,因为Application 的 Context 的生命周期比较长,引用它不会出现内存泄露的问题
在一些场景中,ScollView内会包含多个ListView,可以把listview的高度写死固定下来。
由于ScollView在快速滑动过程中需要大量计算每一个listview的高度,阻塞了UI线程导致卡顿现象出现,如果我们每一个item的高度都是均匀的,可以通过计算把listview的高度确定下来,避免卡顿现象出现使用 RecycleView 代替listview:
每个item内容的变动,listview都需要去调用notifyDataSetChanged来更新全部的item,太浪费性能了。RecycleView可以实现当个item的局部刷新,并且引入了增加和删除的动态效果,在性能上和定制上都有很大的改善ListView 中元素避免半透明:
半透明绘制需要大量乘法计算,在滑动时不停重绘会造成大量的计算,在比较差的机子上会比较卡。 在设计上能不半透明就不不半透明。实在要弄就把在滑动的时候把半透明设置成不透明,滑动完再重新设置成半透明。尽量开启硬件加速:
硬件加速提升巨大,避免使用一些不支持的函数导致含泪关闭某个地方的硬件加速。当然这一条不只是对 ListView。
布局的优化
- 尽量重用一个布局文件,使用include标签,多个相同的布局可以复用
- 减少一个布局的不必要节点
- 尽量使用view自身的参数,例如:Button,有一个可以把图绘制在左边的参数:android:drawableLeft
- 使用< ViewStub />标签来加载一些不常用的布局;使用< merge />标签减少布局的嵌套层次
ViewPager的优化
- viewpager会默认加载左右俩个页面,有时候我们并不想看,会浪费用户的流量,可以在setOnPageChangeListener的onPageSelected的方法里选中哪个页面,初始化哪个页面
- 由于viewpager会默认销毁第三页面,可以强制让viewpager加载所有的页面pagerView.setOffscreenPageLimit(pageCount);,但是如果页面多的话就不能这样干了
- 可以定义一个集合将页面缓存起来,在destroyItem的时候保存起来,在instantiateItem读取集合,有就用,没有的话再创建,就像listview的convertView似的
class HomeAdapter extends PagerAdapter {
// 当前viewPager里面有多少个条目
LinkedList<ImageView> convertView=new LinkedList<ImageView>();
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
/* 判断返回的对象和 加载view对象的关系 */
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
ImageView view=(ImageView) object;
convertView.add(view);// 把移除的对象 添加到缓存集合中
container.removeView(view);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView view;
if(convertView.size()>0){
view=convertView.remove(0);
}else{
view= new ImageView(UiUtils.getContext());
}
bitmapUtils.display(view, HttpHelper.URL + "image?name="
+ datas.get(index));
container.addView(view); // 加载的view对象
return view; // 返回的对象
}
}
内存的优化
- 回收已经使用的资源,比如游标cursor 、I/O、Bitmap(close并且引用置为null)
- 合理的使用缓存,比如图片是很耗内存的,使用lru缓存图片和压缩
- 合理设置变量的作用范围
- 节制的使用服务,后台任务运行完,即使它不执行任何操作,服务也会一直运行,这些是十分消耗内存的,可以用intentservice
- 当界面不可见时释放内存,在activity的onTrimMemory方法里与ui的相关资源,在onstop里释放与组件相关的资源
- 合理的使用多进程,如果后台任务和前台界面是相互独立在,可以在组件标签下写process,这样这个组建就在另一个进程里了。而服务的话更倾向于开启自己所依赖的进城,而那个进程可能很多东西都不需要,比如ui
- 使用线程池、对象池
- Bitmap对象在不使用时,应该先调用recycle()释放内存,然后才它设置为null。
代码优化
这部分就是是细微的优化,但是细微多了也就内存节约了
任何一个Java类,包括内部类、匿名类,都要占用大概500字节的内存空间。
任何一个类的实例要消耗12-16字节的内存开支,因此频繁创建实例也是会一定程序上影响内存的,所以要避免创建不必要的对象
- 如果有一个需要拼接的字符串,那么可以优先考虑使用StringBuffer或者StringBuilder来进行拼接,而不是加号连接符,因为使用加号连接符会创建多余的对象,拼接的字符串越长,加号连接符的性能越低
- 尽量使用基本数据类来代替封装数据类型,int比Integer要更加高效,其它数据类型也是一样
使用静态
- 使用枚举通常会比使用静态常量要消耗两倍以上的内存,在Android开发当中应当尽可能地不使用枚举。
- 如果你并不需要访问一个对象中的某些字段,只是想调用它的某个方法来去完成一项通用的功能,那么可以将这个方法设置成静态方法,这会让调用的速度提升15%-20%,同时也不用为了调用这个方法而去专门创建对象了,这样还满足了上面的一条原则。另外这也是一种好的编程习惯,因为我们可以放心地调用静态方法,而不用担心调用这个方法后是否会改变对象的状态(静态方法内无法访问非静态字段)
对常量使用static final修饰符
使用增强型for循环语法
多使用系统封装好的API,比如:indexOf(),System.arraycopy()
性能优化:尽量使用drawable对象保存图片而不是bitmap
drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");
Android优化指南的更多相关文章
- Unity开发Android应用优化指南(下)
http://forum.china.unity3d.com/thread-27044-1-1.html 在Unity开发Android应用优化指南(上)一文中,从游戏性能,脚本等方面进行了分析和总结 ...
- 阿里无线前端性能优化指南 (Pt.1 加载优化)
前言 阿里无线前端团队在过去一年对所负责业务进行了全面的性能优化.以下是我们根据实际经验总结的优化指南,希望对大家有所帮助. 第一部分仅包括数据加载期优化. 图片控制 对于网页特别是电商类页面来说,图 ...
- 移动H5前端性能优化指南
移动H5前端性能优化指南 概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首屏加载3秒完成或使用Loading4. 基于联通3G网 ...
- web前端性能优化指南(转)
web前端性能优化指南 概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首屏加载3秒完成或使用Loading4. 基于联通3G网络 ...
- 移动H5前端性能优化指南(转载)
移动H5前端性能优化指南 概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首屏加载3秒完成或使用Loading4. 基于联通3G网 ...
- 《Genesis-3D开源游戏引擎完整实例教程-跑酷游戏篇06:移动版优化指南》--本系列完结
6.移动版优化指南 概述: 移动设备不同于目前的高端设备(Wii.Xbox 360和PS3),市场上的手机硬件是很有限的,并且所有的移动设备都是不一样的.像Adroid手机,由于品牌和出厂年限的不同, ...
- 移动H5前端性能优化指南[托尼托尼研究所]
概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首屏加载3秒完成或使用Loading4. 基于联通3G网络平均338KB/s(2. ...
- 移动HTML 5前端性能优化指南(转载)
前端工程师的菜!最近移动Html 5越来越火,想有一个体验流畅的Html 5 应用,这篇优化指南就别放过咯.腾讯的同学将关键的注意点与优化方法都总结出来,全文高能干货,非常值得深度学习 >> ...
- web前端性能优化指南
web前端性能优化指南 web前端性能优化指南 概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首屏加载3秒完成或使用Loadin ...
随机推荐
- 磁盘管理 lvm减容扩容
参考https://blog.csdn.net/wk022/article/details/50543922 新增磁盘/dev/sdb fdisk /dev/sdb 分两个分区 (n p 1 /n ...
- python 打开浏览器的方法 Python打开默认浏览器
一.python 打开浏览器的方法: . startfile方法(打开指定浏览器) import os os.startfile("C:\Program Files\internet exp ...
- 洛谷1027 Car的旅行路线
原题链接 将每个城市拆成四个点,即四个机场来看,那么这题就是求最短路. 不过建图有些麻烦,先要找出第四个机场的坐标. 设另外三个机场的坐标为\((x_1, y_1), (x_2, y_2), (x_3 ...
- node,Yeoman,Bower,Grunt的简介及安装
作为前端,基本的html,css,js已经不太够用了,所以要学习一些前端自动化工具,来提高我们的生产力 1.NodeJS 先安装NodeJS,直接去官网,下载最新的版本,一定要最新的版本,这样会避免很 ...
- mac 下 tomcat7的安装
1.到 apache官方主页 下载 tomcat7 版本的完整 tar.gz 安装包 解压拷贝到 /Library目录下,并命名为Tomcat. 2.修改目录权限,终端输入 sudo chmod ...
- node-sass 不能正常安装解决办法
web前端在安装node包时,总是报错,究其原因是node-sass没有被正常安装. 根本原因是国内网络的原因. 最终的解决方法是通过淘宝的npm镜像安装node-sass 首先安装cnpm npm ...
- Python 打印矩形、直角三角形、等腰三角形、菱形
# 1)打印一个星号 print('*') #2)打印一行6个星号 * * * * * * for i in range(6): print('*',end=' ') #3)打印6列星号 * * * ...
- #实验三 敏捷开发与XP实践---实验报告
一.实验三 敏捷开发与XP实践-1 1.实验要求 -实验三 敏捷开发与XP实践 http://www.cnblogs.com/rocedu/p/4795776.html, Eclipse的内容替换成I ...
- (24)How generational stereotypes hold us back at work
https://www.ted.com/talks/leah_georges_how_generational_stereotypes_hold_us_back_at_work/transcript ...
- python脚本在linux下的执行
假设现有一篇待执行的python脚本test.py python脚本在linux下面执行有两种方式: 打开Linux终端,输入 python test.py 在test.py脚本第一行添加声明 #!/ ...