本文章由cartzhang编写。转载请注明出处。 所有权利保留。

文章链接:http://blog.csdn.net/cartzhang/article/details/55051570

作者:cartzhang

simple pool 博客一的地址:

http://blog.csdn.net/cartzhang/article/details/54096845

一、simpe_pool对象池的问题

在上篇对象池simple_pool中提到了它如今的问题。

一个是数据控制,也就是在单个父亲节点下,仅仅会一直增加来满足当前游戏对对象池内的对象数量的须要,没有考虑到降低。也就是说,若在A阶段,游戏场景中同一时候须要大量的某个池内O1对象,这时候就出现大量的AO1对象在内存中。可是过了A阶段,不须要A这么多O1对象时候,对象池内没有做操作和优化。

还有一个问题,就是多线程的问题。这个暂时不这里讨论。

有须要能够自己先对linkedlist加锁。



本片针对第一个问题。来做了处理。

顺便给出上篇simple_pool博客地址:

http://blog.csdn.net/cartzhang/article/details/54096845

https://github.com/cartzhang/simple_pool_bench

二、对象池内数量优化思路

本着在后台处理,尽量少影响对象池的使用的原则。决定使用在增加一个线程来实现。对须要清理的池内对象进行记录和推断。然后在主线程中进行删除(destroy)操作.



由于Unity不同意在其它自己建立的线程中调用Destroy函数,所以还是要在Update中进行处理。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FydHpoYW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">



这个是自己画的流程图,基本就是这个样子。当然里面详细參数,能够依据自己须要调整。

三、实现代码

1.首先,建立垃圾清理标记和垃圾对象列表。

// garbage clean.
private static bool clearGarbageFlag = false;
private static List<Transform> GarbageList = new List<Transform>(100);

然后标记为真。開始清理。

这里进行了加锁,避免一边删除。一边增加,这样造成野的对象。垃圾表被清空了,对象也不在对象池内列表中。

2.主线程的清理工作

 private void Update()
{
CleanGarbageList();
} private void CleanGarbageList()
{
if (clearGarbageFlag)
{
clearGarbageFlag = false;
lock (GarbageList)
{
Debug.Assert(GarbageList.Count > 0);
Debug.Log("now destroy " + GarbageList.Count + " from pool" + GarbageList[0].name);
for (int i = 0; i < GarbageList.Count; i++)
{
Destroy(GarbageList[i].gameObject);
}
GarbageList.Clear();
}
}
}

3.优化线程启动



线程在第一次调用池的时候開始启动。

然后定时检測数量,每轮会检測checkTimesForEach个对象池内的未使用的情况。对象池个数超出的部分,等待5个中的一个多次检測没有异常后,在增加到检測中,这个主要是为了防止多个对象池内,一次性增加垃圾列表中太多对象。须要一次性删掉的太多,造成主线程卡顿的情况。



当然这也不是最理想的,为了防止卡顿。每次检測循环仅仅检測到一个满足垃圾清理条件,须要处理就会停止检測跳出循环,然后进行垃圾处理。这个也是为了轻量级的删减措施。

一旦成功设置标志。就又一次计算和检測。而且在设置后,优化线程等待1秒时间,来让主线程做工作。这个时间应该是非常充裕的。

主要代码

 private static void OptimizationPool()
{
// check cpu time to start
Thread.Sleep(100);
// 检測间隔时间20秒
float intervalTimeTodetect = 20f;
// after how many times counts to reset count.
// 循环检測多少次。后记录清零。 每次仅仅处理须要处理的前5个池。
const int checkTimesForEach = 5;
// 暂时池管理对象
Dictionary<int, ObjectPool> poolManagerTempDic = new Dictionary<int, ObjectPool>();
System.DateTime timeCount = System.DateTime.Now;
// 间隔时间内运行一次
bool eachMinuteGetDicOnce = false;
// 每一个池未使用对象超过一半的标记,记录次数
Dictionary<int, int> CurrentPoolUnuseCount = new Dictionary<int, int>();
// 检測刷新次数。也是一次计数的最大时间。
int icountLoopTime = 0;
Debug.Log("Thread start");
// 休眠时间
int sleepTime = 10;
while (isStartThread)
{
Thread.Sleep(sleepTime);
if (!eachMinuteGetDicOnce)
{
eachMinuteGetDicOnce = true;
poolManagerTempDic = poolManagerDic.ToDictionary(entry => entry.Key,entry => entry.Value);
// loop check 3 time to reset.
if (icountLoopTime % checkTimesForEach == 0)
{
CurrentPoolUnuseCount.Clear();
icountLoopTime = icountLoopTime > 10000000 ? 0 : icountLoopTime;
} // mark unuse nuber for all.
foreach(var element in poolManagerTempDic)
{
ObjectPool opool = element.Value;
int unusinglinkCount = opool.UnusingLinkedList.Count;
// half of all is useless and more than 10.
if (unusinglinkCount * 2 > unusinglinkCount + opool.UsingLinkedList.Count && unusinglinkCount > 10)
{
MarkCountForUnusingLink(ref CurrentPoolUnuseCount, element.Key);
// satisfy the condition,add unusing link gameobject to garbagelist.
int currentMark = 0;
CurrentPoolUnuseCount.TryGetValue(element.Key,out currentMark);
// be marked three times, add to garbage list.
if (currentMark >= 3)
{
AddObjectsToGarbageList(ref opool.UnusingLinkedList);
// count tick to reset.
CurrentPoolUnuseCount[element.Key] = 0;
clearGarbageFlag = true;
// each time only gathing one pool to process.
break;
}
}
}
}
// leave time for mainthread to delete gameobjects.
if (clearGarbageFlag)
{
icountLoopTime = 0;
intervalTimeTodetect = 20f;
Thread.Sleep(1000);
timeCount = System.DateTime.Now;
} // interval 20 seconds to start check once;
if ((System.DateTime.Now - timeCount).TotalSeconds > intervalTimeTodetect)
{
timeCount = System.DateTime.Now;
eachMinuteGetDicOnce = false;
poolManagerTempDic.Clear();
icountLoopTime++;
Debug.Log("Loop count is " + icountLoopTime);
}
// long time nothing happen, expand the detective interval time (max <= 90s).
if (icountLoopTime >= 4 )
{
intervalTimeTodetect = intervalTimeTodetect * 2 >= 90f ? 90f : intervalTimeTodetect * 2;
icountLoopTime = 0;
Debug.Log("interval time is " + intervalTimeTodetect);
}
}
return;
} /// <summary>
/// add last gameobject to garbagelist,as when unsing unusinglink is from first place to get.
/// </summary>
/// <param name="list"></param>
private static void AddObjectsToGarbageList(ref LinkedList<Transform> list)
{
Debug.Assert(list.Count > 0);
int FlagDestroyNumber = list.Count>>1;
for (int i = 0; i < FlagDestroyNumber; i++)
{
GarbageList.Add(list.Last.Value);
list.RemoveLast();
}
}

依照眼下设置參数,開始检測的时间间隔为20秒,若20*2=40秒后,没有须要处理的垃圾,就把检測时间间隔翻倍为40秒检測一次;若在过40*4=160秒,没有触发标志。检測时间进一步延长,逐次翻倍增加。可是最大值为90秒。

也就是说。最大的检測间隔为90秒。



若中间被打断。所有归为正常20秒检測一次。

触发增加垃圾列表的条件:



设置触发标志是一个池,在3次检測中都有超过一半的对象没有被使用,而且总体未使用数量超过10个。

四、更新project分享地址:

地址:https://github.com/cartzhang/simple_pool_bench



能够下载Assets文件。然后用unity測试。



这个測试demo为 PoolTimeOptimizeOjbectsDemo.unity。



优化流程图下载地址:

https://github.com/cartzhang/simple_pool_bench/blob/master/img/pool_bench_optimize.png



若有问题,请提交问题或代码。非常感谢!

。!

五、附件

poolManager.cs 所有代码:

using UnityEngine;
using System.Collections.Generic;
using SLQJ_POOL;
using UnityEngine.Internal;
using System.Threading;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Linq; /// <summary>
/// 扩展GameObject函数
/// 使用扩展函数方面代码调用,能够Unity的随意代码中,调用对象池来产生和回池对象,
/// 而且不须要调用命名空间等繁琐东西。 /// 代码样例: obj = gameObject.InstantiateFromPool(prefab);
/// gameObject.DestroyToPool(poolObjs[poolObjs.Count - 1], 0.2f);
/// 详细能够參考HowToUse脚本和TestEffect。 /// @cartzhang
/// </summary>
public static class GameObjectExten
{
/// <summary>
/// 调用对象池,产生一对象,并带有位置和旋转等參考
/// </summary>
/// <param name="gameobject"></param>
/// <param name="original"></param>
/// <param name="position"></param>
/// <param name="rotation"></param>
/// <returns></returns>
public static GameObject InstantiateFromPool(this GameObject gameobject, Object original, Vector3 position, Quaternion rotation)
{
return PoolManager.PullObjcetFromPool(original as GameObject, position, rotation).gameObject;
}
/// <summary>
/// 调用对象池,产生对象
/// </summary>
/// <param name="gameobject"></param>
/// <param name="original"></param>
/// <returns></returns>
public static GameObject InstantiateFromPool(this GameObject gameobject, Object original)
{
return PoolManager.PullObjcetFromPool(original as GameObject).gameObject;
}
/// <summary>
/// 对象返回对象池
/// </summary>
/// <param name="gameobject"></param>
/// <param name="obj"></param>
public static void DestroyToPool(this GameObject gameobject, Object obj)
{
PoolManager.PushObjectPool((obj as GameObject).transform);
}
/// <summary>
/// 带延时的返回对象池
/// </summary>
/// <param name="gameobject"></param>
/// <param name="obj"></param>
/// <param name="t"></param>
public static void DestroyToPool(this GameObject gameobject, Object obj, [DefaultValue("0.0F")] float t)
{
PoolManager.PushObjectPool((obj as GameObject).transform, t);
}
} namespace SLQJ_POOL
{
public class PoolManager : MonoBehaviour
{
private static PoolManager instance;
private static bool bStartThreadOnce = false;
private static bool isStartThread = false;
private static Thread tOptimizationThread; private static List<GameObject> prefabList = new List<GameObject>();
//存放预制体相应的id。ObjcetPool
public static Dictionary<int, ObjectPool> poolManagerDic = new Dictionary<int, ObjectPool>();
private static Dictionary<Transform, ObjectPool> transformDic = new Dictionary<Transform, ObjectPool>();
// garbage clean.
private static bool clearGarbageFlag = false;
private static List<Transform> GarbageList = new List<Transform>(100);
private void Update()
{
CleanGarbageList();
} private void CleanGarbageList()
{
if (clearGarbageFlag)
{
clearGarbageFlag = false;
lock (GarbageList)
{
Debug.Assert(GarbageList.Count > 0);
Debug.Log("now destroy " + GarbageList.Count + " from pool" + GarbageList[0].name);
for (int i = 0; i < GarbageList.Count; i++)
{
Destroy(GarbageList[i].gameObject);
}
GarbageList.Clear();
}
}
} //初始化某个预制体相应的对象池
public static void InitPrefab(GameObject prefab, int initNum = 4)
{
GetObjectPool(prefab, initNum);
}
//外界调用的接口
public static Transform PullObjcetFromPool(GameObject prefab)
{
return _PullObjcetFromPool(prefab);
}
public static Transform PullObjcetFromPool(GameObject prefab, Vector3 pos, Quaternion quaternion)
{
return _PullObjcetFromPool(prefab, pos, quaternion);
}
private static Transform _PullObjcetFromPool(GameObject prefab)
{
if (prefab == null)
{
Debug.Log("prefab is null!");
return null;
}
ObjectPool objPool = GetObjectPool(prefab);
StartThreadOnce();
return objPool.PullObjcetFromPool();
} private static Transform _PullObjcetFromPool(GameObject prefab, Vector3 pos, Quaternion quaternion)
{
if (prefab == null)
{
Debug.Log("prefab is null!");
return null;
}
ObjectPool objPool = GetObjectPool(prefab, pos, quaternion);
StartThreadOnce();
return objPool.PullObjcetFromPool(pos, quaternion);
} private static ObjectPool GetObjectPool(GameObject prefab, int initNum = 4)
{
ObjectPool objPool = null;
//推断集合中是否有预制体相应的对象池
int leng = prefabList.Count;
int prefabID = prefab.GetInstanceID();
for (int i = 0; i < leng; i++)
{
if (prefabID == prefabList[i].GetInstanceID())
{
objPool = poolManagerDic[prefabID];
break;
}
}
//没有找到对象池的话创建一个对象池
if (objPool == null)
{
objPool = CreatObjcetPool(prefab, initNum);
}
return objPool;
} private static ObjectPool GetObjectPool(GameObject prefab, Vector3 pos, Quaternion qua, int initNum = 4)
{
ObjectPool objPool = null;
int leng = prefabList.Count;
int prefabID = prefab.GetInstanceID();
for (int i = 0; i < leng; i++)
{
if (prefabID == prefabList[i].GetInstanceID())
{
objPool = poolManagerDic[prefabID];
}
}
if (objPool == null)
{
objPool = CreatObjcetPool(prefab, pos, qua, initNum);
}
return objPool;
} private static ObjectPool CreatObjcetPool(GameObject prefab, Vector3 pos, Quaternion qua, int initNum)
{
prefabList.Add(prefab);
GameObject go = new GameObject();
go.name = prefab.name + "Pool";
ObjectPool objPool = go.AddComponent<ObjectPool>();
objPool.InitObjectPool(prefab, pos, qua, transformDic, initNum);
poolManagerDic.Add(prefab.GetInstanceID(), objPool);
return objPool;
} private static ObjectPool CreatObjcetPool(GameObject prefab, int initNum)
{
prefabList.Add(prefab);
GameObject go = new GameObject();
go.name = prefab.name + "Pool";
ObjectPool objPool = go.AddComponent<ObjectPool>();
objPool.InitObjectPool(prefab, transformDic, initNum);
poolManagerDic.Add(prefab.GetInstanceID(), objPool);
return objPool;
} public static void PushObjectPool(Transform handleTransform)
{
ObjectPool objPool = GetPoolByTransform(handleTransform);
if (objPool)
{
objPool.PushObjectToPool(handleTransform);
}
else
{
GameObject.Destroy(handleTransform.gameObject);
}
}
public static void PushObjectPool(Transform handleTransform, float delayTime)
{
ObjectPool objPool = GetPoolByTransform(handleTransform);
if (objPool)
{
objPool.PushObjectToPool(handleTransform, delayTime);
}
else
{
GameObject.Destroy(handleTransform.gameObject, delayTime);
}
}
//马上回池的接口
public static void PushObjectPool(Transform handleTransform, GameObject prefab)
{
ObjectPool objPool = GetObjectPool(prefab);
objPool.PushObjectToPool(handleTransform.transform);
}
//延迟回池的接口
public static void PushObjectPool(Transform handleTransform, GameObject prefab, float delayTime)
{
ObjectPool objPool = GetObjectPool(prefab);
objPool.PushObjectToPool(handleTransform, delayTime);
} private static ObjectPool GetPoolByTransform(Transform handleTransform)
{
if (transformDic.ContainsKey(handleTransform))
{
return transformDic[handleTransform];
}
Debug.LogError(handleTransform.name + " no find it's ObjectPool");
return null;
}
// add code to clean pool from time to time.
private static void StartThreadOnce()
{
// start thread to clean pool from time to time.
if (!bStartThreadOnce)
{
bStartThreadOnce = true;
ThreadPool.QueueUserWorkItem(AutoToCheckOptimization);
}
} private static void AutoToCheckOptimization(object obj)
{
Thread.Sleep(10);
isStartThread = true;
tOptimizationThread = new Thread(OptimizationPool);
tOptimizationThread.Start();
} private static void OptimizationPool()
{
// check cpu time to start
Thread.Sleep(100);
// 检測间隔时间20秒
float intervalTimeTodetect = 20f;
// after how many times counts to reset count.
// 循环检測多少次,后记录清零。每次仅仅处理须要处理的前5个池。
const int checkTimesForEach = 5;
// 暂时池管理对象
Dictionary<int, ObjectPool> poolManagerTempDic = new Dictionary<int, ObjectPool>();
System.DateTime timeCount = System.DateTime.Now;
// 间隔时间内运行一次
bool eachMinuteGetDicOnce = false;
// 每一个池未使用对象超过一半的标记,记录次数
Dictionary<int, int> CurrentPoolUnuseCount = new Dictionary<int, int>();
// 检測刷新次数。也是一次计数的最大时间。 int icountLoopTime = 0;
Debug.Log("Thread start");
// 休眠时间
int sleepTime = 10;
while (isStartThread)
{
Thread.Sleep(sleepTime);
if (!eachMinuteGetDicOnce)
{
eachMinuteGetDicOnce = true;
poolManagerTempDic = poolManagerDic.ToDictionary(entry => entry.Key,entry => entry.Value);
// loop check 3 time to reset.
if (icountLoopTime % checkTimesForEach == 0)
{
CurrentPoolUnuseCount.Clear();
icountLoopTime = icountLoopTime > 10000000 ? 0 : icountLoopTime;
} // mark unuse nuber for all.
foreach(var element in poolManagerTempDic)
{
ObjectPool opool = element.Value;
int unusinglinkCount = opool.UnusingLinkedList.Count;
// half of all is useless and more than 10.
if (unusinglinkCount * 2 > unusinglinkCount + opool.UsingLinkedList.Count && unusinglinkCount > 10)
{
MarkCountForUnusingLink(ref CurrentPoolUnuseCount, element.Key);
// satisfy the condition,add unusing link gameobject to garbagelist.
int currentMark = 0;
CurrentPoolUnuseCount.TryGetValue(element.Key,out currentMark);
// be marked three times, add to garbage list.
if (currentMark >= 3)
{
AddObjectsToGarbageList(ref opool.UnusingLinkedList);
// count tick to reset.
CurrentPoolUnuseCount[element.Key] = 0;
clearGarbageFlag = true;
// each time only gathing one pool to process.
break;
}
}
}
}
// leave time for mainthread to delete gameobjects.
if (clearGarbageFlag)
{
icountLoopTime = 0;
intervalTimeTodetect = 20f;
Thread.Sleep(1000);
timeCount = System.DateTime.Now;
} // interval 20 seconds to start check once;
if ((System.DateTime.Now - timeCount).TotalSeconds > intervalTimeTodetect)
{
timeCount = System.DateTime.Now;
eachMinuteGetDicOnce = false;
poolManagerTempDic.Clear();
icountLoopTime++;
Debug.Log("Loop count is " + icountLoopTime);
}
// long time nothing happen, expand the detective interval time (max <= 90s).
if (icountLoopTime >= 4 )
{
intervalTimeTodetect = intervalTimeTodetect * 2 >= 90f ? 90f : intervalTimeTodetect * 2;
icountLoopTime = 0;
Debug.Log("interval time is " + intervalTimeTodetect);
}
}
return;
} private static void MarkCountForUnusingLink(ref Dictionary<int, int> poolUnuseCount,int prefabGuid)
{
Debug.Assert(null != poolManagerDic);
int currentMark = 0;
if (poolUnuseCount.ContainsKey(prefabGuid))
{
poolUnuseCount.TryGetValue(prefabGuid, out currentMark);
}
currentMark++;
if (poolUnuseCount.ContainsKey(prefabGuid))
{
poolUnuseCount[prefabGuid] = currentMark;
}
else
{
poolUnuseCount.Add(prefabGuid, currentMark);
}
} /// <summary>
/// add last gameobject to garbagelist,as when unsing unusinglink is from first place to get.
/// </summary>
/// <param name="list"></param>
private static void AddObjectsToGarbageList(ref LinkedList<Transform> list)
{
Debug.Assert(list.Count > 0);
int FlagDestroyNumber = list.Count>>1;
for (int i = 0; i < FlagDestroyNumber; i++)
{
GarbageList.Add(list.Last.Value);
list.RemoveLast();
}
} public void Dispose()
{
isStartThread = false;
}
}
}

simple_pool对象池——优化&lt;二&gt;的更多相关文章

  1. Unity 游戏框架搭建 (二十) 更安全的对象池

    上篇文章介绍了,只需通过实现IObjectFactory接口和继承Pool类,就可以很方便地实现一个SimpleObjectPool.SimpleObjectPool可以满足大部分的对象池的需求.而笔 ...

  2. 二十、dbms_stats(用于搜集,查看,修改数据库对象的优化统计信息)

    1.概述 作用:用于搜集,查看,修改数据库对象的优化统计信息. 2.包的组成 1).get_column_stats作用:用于取得列的统计信息语法:dbms_stats.get_column_stat ...

  3. Unity性能优化-对象池

    1.对象池Object Pool的原理: 有些GameObject是在游戏中需要频繁生成并销毁的(比如射击游戏中的子弹),以前的常规做法是:Instantiate不断生成预设件Prefab,然后采用碰 ...

  4. Mysql线程池优化笔记

    Mysql线程池优化我是总结了一个站长的3篇文章了,这里我整理到一起来本文章就分为三个优化段了,下面一起来看看.     Mysql线程池系列一(Thread pool FAQ) 首先介绍什么是mys ...

  5. Unity 对象池的使用

    在游戏开发过程中,我们经常会遇到游戏发布后,测试时玩着玩着明显的感觉到有卡顿现象.出现这种现象的有两个原因:一是游戏优化的不够好或者游戏逻辑本身设计的就有问题,二是手机硬件不行.好吧,对于作为程序员的 ...

  6. Unity 游戏框架搭建 (十九) 简易对象池

    在Unity中我们经常会用到对象池,使用对象池无非就是解决两个问题: 一是减少new时候寻址造成的消耗,该消耗的原因是内存碎片. 二是减少Object.Instantiate时内部进行序列化和反序列化 ...

  7. Java小对象的解决之道——对象池(Object Pool)的设计与应用

    一.概述 面向对象编程是软件开发中的一项利器,现已经成为大多数编程人员的编程思路.很多高级计算机语言也对这种编程模式提供了很好的支持,例如C++.Object Pascal.Java等.曾经有大量的软 ...

  8. 大数据技术之_27_电商平台数据分析项目_02_预备知识 + Scala + Spark Core + Spark SQL + Spark Streaming + Java 对象池

    第0章 预备知识0.1 Scala0.1.1 Scala 操作符0.1.2 拉链操作0.2 Spark Core0.2.1 Spark RDD 持久化0.2.2 Spark 共享变量0.3 Spark ...

  9. netty源码分析 - Recycler 对象池的设计

    目录 一.为什么需要对象池 二.使用姿势 2.1 同线程创建回收对象 2.2 异线程创建回收对象 三.数据结构 3.1 物理数据结构图 3.2 逻辑数据结构图(重要) 四.源码分析 4.2.同线程获取 ...

随机推荐

  1. TaobaoVM

    作者:Andoter链接:https://www.zhihu.com/question/275665265/answer/416021488来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商 ...

  2. java Iterable

    Iterable

  3. AOJ 0531:Paint Color(二维离散+imos)

    [题目链接] http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0531 [题目大意] 给出一张图,和一些矩形障碍物,求该图没被障碍物覆 ...

  4. 【bzoj1951】【古代猪文】Lucas定理+欧拉定理+孙子定理

    (上不了p站我要死了,当然是游戏原画啊) Description (题面倒是很有趣,就是太长了) 题意: 一个朝代流传的猪文文字恰好为N的k分之一,其中k是N的一个正约数(可以是1和N).不过具体是哪 ...

  5. iframe和response.sendRedirect()跳转到父页面的问题

    在项目中,因为为了给页面分层次,就使用了 内嵌iframe 的分了三个框.在子页面进行操作的时候,如果session超时,就要被拦截器拦截重新回到首页进行登录,但是在sub页 面 ,进行操作的时候,如 ...

  6. 在java代码中设置margin

    我们平常可以直接在xml里设置margin,如: <ImageView android:layout_margin="5dip" android:src="@dra ...

  7. iOS8使用TestFlight进行内部测试功能尝鲜

    iOS8发布了有一段时间了,我们的策划很新潮的速度给升级到iOS8了.于是XCode5不支持了,只好从MacOS 10.8升级到10.9,再升级到10.9.5,再下载XCode6安装…… 然后前两天上 ...

  8. linux 远程同步数据工具rsync (1)

    rsync 远程同步数据工具,是linux下的数据备份工具rsync(remote sync 远程同步) 特点:在本地同步数据(类似于cp,但是有不同于远程scp),它会先判断已经存在的数据和远程数据 ...

  9. 文件流:"fopen","fclose",“ftell”"fseek","fgets","fprintf" ,“feof”,"fwrite","fread"

    char const* filename="D:/hello.txt"; 路径名使用的是“/”或者使用 转义字符“\\”: "fopen", FILE *fp= ...

  10. 控制流程完整性:给大家介绍一种“另类”的Javascript反分析技术

    写在前面的话 理解恶意软件的真实代码对恶意软件分析人员来说是非常有优势的,因为这样才能够真正了解恶意软件所要做的事情.但不幸的是,我们并不总是能够得到“真实”的代码,有时恶意软件分析人员可能需要类似反 ...