当前位置: 首页 > wzjs >正文

网站怎么优化自己免费企业网站改版项目描述

网站怎么优化自己免费,企业网站改版项目描述,新塘17网站一起做网店官网,塘下做网站一:背景 1. 讲故事 如果你读完前六篇,我相信你对 harmony 的简单使用应该是没什么问题了,现在你处于手拿锤子看谁都是钉子的情况,那这篇我就找高级调试里非常经典的 3个钉子 让大家捶一锤。 二:三大故障案例 1. Co…

一:背景

1. 讲故事

如果你读完前六篇,我相信你对 harmony 的简单使用应该是没什么问题了,现在你处于手拿锤子看谁都是钉子的情况,那这篇我就找高级调试里非常经典的 3个钉子 让大家捶一锤。

二:三大故障案例

1. ConcurrentBag 大集合问题

在高级调试中经常会遇到一类问题就是托管内存暴涨,最终在托管堆上发现了超大的一个集合,windbg 输出如下:


0:014> !gcroot 028266c9ff30
HandleTable:0000028262d51328 (strong handle)-> 0282675459a0     System.Object[] -> 0282675459c8     System.Threading.ThreadLocal<System.Collections.Concurrent.ConcurrentBag<Example_20_1_1.Student>+WorkStealingQueue>+LinkedSlotVolatile[] -> 028267545a00     System.Threading.ThreadLocal<System.Collections.Concurrent.ConcurrentBag<Example_20_1_1.Student>+WorkStealingQueue>+LinkedSlot -> 028267545a30     System.Collections.Concurrent.ConcurrentBag<Example_20_1_1.Student>+WorkStealingQueue -> 028267fe0198     Example_20_1_1.Student[] -> 028266c9ff30     Example_20_1_1.Student 0:014> !dumpobj /d 28267545a30
Name:        System.Collections.Concurrent.ConcurrentBag`1+WorkStealingQueue[[Example_20_1_1.Student, Example_20_1_1]]
File:        C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.13\System.Collections.Concurrent.dll
Fields:MT    Field   Offset                 Type VT     Attr            Value Name
00007fff8fc31188  4000017       18         System.Int32  1 instance                0 _headIndex
00007fff8fc31188  4000018       1c         System.Int32  1 instance          1000000 _tailIndex
00007fff8fe76168  4000019        8     System.__Canon[]  0 instance 0000028267fe0198 _array
...

从windbg的输出中可以看到ConcurrentBag中有100w条记录,现在我就特别想知道,这个ConcurrentBag的变量是什么,谁在不断的Add操作?这刚好是 harmony 的大显神威之处,由于引用类型的泛型参数统一由__Canon替代,这里我就使用它的基类 object,参考代码如下:


namespace Example_20_1_1
{internal class Program{static void Main(string[] args){var harmony = new Harmony("com.example.threadhook");harmony.PatchAll();RunWork();Console.ReadLine();}static void RunWork(){ConcurrentBag<Student> studentBags = new ConcurrentBag<Student>();studentBags.Add(new Student() { Id = 1 });studentBags.Add(new Student() { Id = 2 });ConcurrentBag<Person> personBags = new ConcurrentBag<Person>();personBags.Add(new Person() { Id = 1 });}}[HarmonyPatch(typeof(ConcurrentBag<object>), "Add", new Type[] { typeof(object) })]public class ConcurrentBagHook{public static void Prefix(object __instance) { }public static void Postfix(object __instance, object __0){var count = Traverse.Create(__instance).Property("Count").GetValue<int>();Console.WriteLine($"泛型参数:{__0.GetType()},当前Count={count}");Console.WriteLine(Environment.StackTrace);}}public class Student { public int Id { get; set; } }public class Person { public int Id { get; set; } }
}

从卦中可以看到不同类型的 ConcurrentBag 的集合元素数,以及对应的上层调用栈,根据调用栈自然就能找到问题,即使它是在第三方sdk中。

2. 非主线程创建UI控件导致卡死

这个问题是 wpf/winform 常遇到的经典问题,介绍的再多也不为过,凡是遇到这种经典都会有这样的调用栈。


0:000:x86> !clrstack
OS Thread Id: 0x4eb688 (0)
Child SP       IP Call Site
002fed38 0000002b [HelperMethodFrame_1OBJ: 002fed38] System.Threading.WaitHandle.WaitOneNative(System.Runtime.InteropServices.SafeHandle, UInt32, Boolean, Boolean)
002fee1c 5cddad21 System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle, Int64, Boolean, Boolean)
002fee34 5cddace8 System.Threading.WaitHandle.WaitOne(Int32, Boolean)
002fee48 538d876c System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle)
002fee88 53c5214a System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean)
002fee8c 538dab4b [InlinedCallFrame: 002fee8c] 
002fef14 538dab4b System.Windows.Forms.Control.Invoke(System.Delegate, System.Object[])
002fef48 53b03bc6 System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback, System.Object)
002fef60 5c774708 Microsoft.Win32.SystemEvents+SystemEventInvokeInfo.Invoke(Boolean, System.Object[])
002fef94 5c6616ec Microsoft.Win32.SystemEvents.RaiseEvent(Boolean, System.Object, System.Object[])
002fefe8 5c660cd4 Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(Int32, IntPtr, IntPtr)
002ff008 5c882c98 Microsoft.Win32.SystemEvents.WindowProc(IntPtr, Int32, IntPtr, IntPtr)
...

底层原理我在 https://www.cnblogs.com/huangxincheng/p/18668388 这一篇中跟大家详细聊过,这里就不细说了,在这里我只要追踪到那个不该出生的control 就算赢了,即Application下的内部类 MarshalingControl,参考代码如下:


namespace WindowsFormsApp1
{public partial class Form1 : Form{public Form1(){InitializeComponent();var harmony = new Harmony("com.example.marshalingcontrolhook");harmony.PatchAll();}private void Form1_Load(object sender, EventArgs e) { }private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e){Button btn = new Button();var query = btn.Handle;}private void button1_Click(object sender, EventArgs e){backgroundWorker1.RunWorkerAsync();}}[HarmonyPatch]public class MarshalingControlHook{[HarmonyTargetMethod]static MethodBase TargetMethod(){var methodInfo = AccessTools.Inner(typeof(Application), "MarshalingControl").Constructor();return methodInfo;}public static void Prefix(){Debug.WriteLine("----------------------------");Debug.WriteLine($"控件创建线程:{Thread.CurrentThread.ManagedThreadId}");Debug.WriteLine(Environment.StackTrace);Debug.WriteLine("----------------------------");}}
}

从卦中可以轻松的看到,原来是用户代码 backgroundWorker1_DoWork 创建的 MarshalingControl 类,自此真相大白。

3. 孤儿锁问题

在大家的潜意识中都会认为lock锁都是有进有出,但在真实的场景下也会存在 有进没出 的情况,那是什么场景呢?对,就是 lock 处理非托管代码的时候,如果非托管代码意外让当前线程退出,就会遇到这种经典的 孤儿锁 现象,参考代码如下:

internal class Program{[DllImport("Example_20_1_5", CallingConvention = CallingConvention.Cdecl)]public extern static void dowork();public static object lockMe = new object();static void Main(string[] args){var harmony = new Harmony("com.example.monitorhook");harmony.PatchAll();for (int i = 0; i < 3; i++){Task.Run(() =>{lock (lockMe){Console.WriteLine("1. 调用 C++ 代码...");dowork();Console.WriteLine("2. C++ 代码执行完毕...");}});}Console.ReadLine();}}

代码中的 dowork 是由 C 实现的,参考如下:


extern "C"
{_declspec(dllexport) void dowork();
}#include "iostream"
#include <Windows.h>using namespace std;void dowork()
{ExitThread(0);
}

启动程序后,你会发现 !syncblk 中对object的持有线程丢了。。。一旦丢失,就会污染 object的对象头,导致其他线程一直等待 持有线程 的释放,最终引发程序卡死的灾难后果,参考如下:


0:008> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info  SyncBlock Owner1 02D562D4            5         1 02D4D400 0 XXX   0504c1b0 System.Object
-----------------------------
Total           2
CCW             0
RCW             0
ComClassFactory 0
Free            0

上面的XXX就是丢失的持有线程,接下来的问题就是洞察到底是哪个线程持有锁之后意外退出了。。。这也是 harmony 的强项,我们对 lock 的底层 Monitor.Enter 进行监控,通过 object 的内存地址观察当初是谁调用的,修改后的完整代码如下:

internal class Program{[DllImport("Example_20_1_5", CallingConvention = CallingConvention.Cdecl)]public extern static void dowork();public static object lockMe = new object();static void Main(string[] args){var harmony = new Harmony("com.example.monitorhook");harmony.PatchAll();for (int i = 0; i < 3; i++){Task.Run(() =>{lock (lockMe){Console.WriteLine("1. 调用 C++ 代码...");dowork();Console.WriteLine("2. C++ 代码执行完毕...");}});}Console.ReadLine();}}[HarmonyPatch]public class MonitorHook{[HarmonyTargetMethod]static MethodBase TargetMethod(){var enterMethodInfo = AccessTools.Method(typeof(Monitor), "Enter", new[] { typeof(object), typeof(bool).MakeByRefType() });return enterMethodInfo;}public static unsafe void Postfix(object obj){void** ptr = (void**)Unsafe.AsPointer(ref obj);//注意:不要使用带 lock 的底层方法,否则会导致 死循环,建议将内容通过 c++ 写入。Debug.WriteLine("-----------------------");Debug.WriteLine($"对象引用地址: 0x{(long)(*ptr):X8} , tid={Thread.CurrentThread.ManagedThreadId}, 调用栈:\n {Environment.StackTrace}");Debug.WriteLine("-----------------------");}}

程序执行后,观察 output 和 windbg 的输出信息,参考如下:


-----------------------
对象引用地址: 0x057CCFD8 , tid=4, 调用栈:at System.Environment.get_StackTrace()at Example_20_1_1.MonitorHook.Postfix(Object obj) in D:\skyfly\20.20250116\src\Example\Example_20_1_1\Program.cs:line 61at System.Threading.Monitor.Enter_Patch1(Object obj, Boolean& lockTaken)at Example_20_1_1.Program.<>c.<Main>b__2_0() in D:\skyfly\20.20250116\src\Example\Example_20_1_1\Program.cs:line 31at System.Threading.Tasks.Task.InnerInvoke()at System.Threading.Tasks.Task.<>c.<.cctor>b__281_0(Object obj)at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)at System.Threading.Tasks.Task.ExecuteEntryUnsafe(Thread threadPoolThread)at System.Threading.Tasks.Task.ExecuteFromThreadPool(Thread threadPoolThread)at System.Threading.ThreadPoolWorkQueue.Dispatch()at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()at System.Threading.Thread.StartCallback()
-----------------------
0:008> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info  SyncBlock Owner5 0AE90184            5         1 035EC578 0 XXX   057ccfd8 System.Object
-----------------------------
Total           6
CCW             0
RCW             0
ComClassFactory 0
Free            0

根据上面调用栈的输出结果,原来这个 057ccfd8 的 object 是由 b__2_0 方法调用的,在真实场景中可能有多处,不过此时我们把范围已经缩小到了极致。

这里还有一个告警点,即我用了 Debug.WriteLine 而没有使用 Console.WriteLine 是因为后者本身就带有锁,使用的话就直接死循环了,建议大家写一个C的导出函数来输出内容。

三:总结

本篇列出的3个案例在.NET高级调试领域中还是非常经典的,如果用的合适,相信对你找出程序的疑难杂症事半功倍。

.NET外挂系列:7. harmony在高级调试中的一些实战案例


文章转载自:

http://df6AxvAl.gtmdq.cn
http://IwG2R2Tb.gtmdq.cn
http://XMIrokdt.gtmdq.cn
http://LAggyXYk.gtmdq.cn
http://xdgAF5Yi.gtmdq.cn
http://Ec44DimA.gtmdq.cn
http://EiIpDLaQ.gtmdq.cn
http://MAcU9vXP.gtmdq.cn
http://aWbUPno3.gtmdq.cn
http://zr50dlTT.gtmdq.cn
http://R0AVaXij.gtmdq.cn
http://NQssTz3y.gtmdq.cn
http://y5xeK6fc.gtmdq.cn
http://9JTsJHDb.gtmdq.cn
http://oHhhdZeQ.gtmdq.cn
http://RRWoxMBq.gtmdq.cn
http://kOPMaTYk.gtmdq.cn
http://sOA50Hcb.gtmdq.cn
http://9mXHtSn8.gtmdq.cn
http://QiPYNUGd.gtmdq.cn
http://Za36t8OZ.gtmdq.cn
http://t41UPOSp.gtmdq.cn
http://EyUyNKCR.gtmdq.cn
http://kHztZW3L.gtmdq.cn
http://ra9UYYvj.gtmdq.cn
http://jTVEOlMr.gtmdq.cn
http://mQe1D9oM.gtmdq.cn
http://27PT6ITG.gtmdq.cn
http://59xKleZj.gtmdq.cn
http://ZoGw7VFd.gtmdq.cn
http://www.dtcms.com/wzjs/629856.html

相关文章:

  • 企业组织网站建设方案电子商务网站建设公
  • 加强人社网站建设合肥企业网站建设公司
  • seo网站三要素怎么做wordpress个性化后台
  • 化妆品销售网站开发与设计产品设计公司推荐
  • 和淘宝同时做电商的网站光明网站建设
  • 网站 建设ppt代加工手工活外发免费 来料加工
  • 做贷款网站犯法吗长沙网站建设外包
  • 软件ui设计怎么做网站找图做素材啥网站好
  • 在58做网站推广有效果吗国外知名网站
  • 网站怎么建设与管理WordPress建站布置
  • 上海自适应网站开发挣钱最快的app
  • 高端网站建设制作设计分销电商
  • 手机中国建设银行网站h5免费制作平台火蚁邀请函
  • 合肥 做网站的qq企业邮箱注册申请
  • 众筹网站搭建深圳定制钻戒哪里好推荐
  • 临淄网站建设价格网站开发前台后台
  • 怎么建设网站赚钱手机广告创意设计大赛
  • 建设网站建站镇江网站建设
  • 做网站的经验一个公司做两个网站的多吗
  • 七宝做网站苏州网站建设推广服务
  • 网站是否必须做可信网站认证郑州有免费建网站的公司吗
  • 网站建设cms系统专业建站公司联系方式
  • 做搜狗pc网站优化模板号专注于网站
  • 网站开发和网页设计遵义网站建设公司有哪些
  • 江宁做网站网站地图制作方法
  • 网站页面设计工作流程注册网站需要多少
  • 招聘网站做招聘顾问网站建设服务费的摊销期限
  • 使用动易模版制作网站课程建设网站设计源码
  • Seo与网站推广的技术对比seo优化易下拉排名
  • 个人备案网站可以做产品推广溧阳市建设工程质量监督站网站