菜鸟请教有关程序运行时内存占用方面的问题

54phoenix 2015-02-08 10:56:58
C#初学小白,请教几个问题,请前辈指点,多谢!
要写个程序持续的每秒ping一个IP用以监控网络,期间如果有没ping通的时候输出时间,用户结束程序时计算丢包率等。
源代码如下(做过简化),主要思路是通过timer计时器每秒调用theout方法,theout方法为ping指定IP
写完测试时发现有关内存方面的问题:
1.当ping1放在theout方法内,程序运行没有问题,但在.NET3.5下运行时内存会持续增加,而在4.0下运行内存则是不断循环变化,不知3.5和4.0为何有这区别?
2.当ping1放在theout方法外,如果从不丢包,则程序调试运行没问题,且不管是3.5还是4.0下运行内存都能维持在一个较低水平不变,貌似比较完美,但如果有ping不通的情况时就会出现调试错误,因为ping不通时该线程需要五秒左右才能结束,而下一秒一个新的线程又开始ping了,就会在“ping1.SendAsync("127.0.0.1", null);”这句报“异步调用已在进行中。必须先完成或者取消此调用,然后才能调用此方法。”错误(将IP改成任意ping不通的即可测试),不知这种情况有没有其他好的处理方法(当然不是1中的方法)。

内存变化情况如下:
框架_变量位置 开始运行时内存 运行1小时内存情况
3.5_in: 2,740K 240,000K左右,且一直持续增加,每秒增加几十K左右
3.5_out: 2,712K 3,400K,且几乎维持不变
4.0_in: 2,964K 循环变化,先每秒增加几十K到一定值(如31,000K)后回落(如4,700K),重复过程
4.0_out: 2,948K 3,580K,且几乎维持不变

源码如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.NetworkInformation;

namespace MemTest
{
class Program
{
Ping ping1 = new Ping();//如果将ping1放在theout方法外面,结果见3.5或4.0_out

static void Main(string[] args)
{
Program p1 = new Program();

System.Timers.Timer t = new System.Timers.Timer();
//订阅t.Elapsed事件发生时执行theout方法
t.Elapsed += new System.Timers.ElapsedEventHandler(p1.theout);
//间隔时间,毫秒
t.Interval = 1000;
//设置是执行一次(false)还是一直执行(true);
t.AutoReset = true;
//是否执行System.Timers.Timer.Elapsed事件;
t.Enabled = true;
Console.Read();
}

private void theout(object source, System.Timers.ElapsedEventArgs e)
{
//Ping ping1 = new Ping();//如果将ping1放在theout方法里面,结果见3.5或4.0_in
ping1.SendAsync("127.0.0.1", null);
}
}
}
...全文
374 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
hitlx 2016-08-08
  • 打赏
  • 举报
回复
多谢楼主的解决方案分享!还有各位大牛的经典分析。
54phoenix 2015-02-10
  • 打赏
  • 举报
回复
最终发现一个不错的方法,可以在3.5版本下ping间隔很短不会出错,内存占用也一直维持在很低的水平。 方法很简单,就是把“Ping ping1 = new Ping()”放在方法内的using()里面,代码如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.NetworkInformation;
 
namespace MemTest
{
    class Program
    {
        //Ping ping1 = new Ping();
 
        static void Main(string[] args)
        {
            Program p1 = new Program();
 
            System.Timers.Timer t = new System.Timers.Timer();
            //订阅t.Elapsed事件发生时执行theout方法 
            t.Elapsed += new System.Timers.ElapsedEventHandler(p1.theout);
            //间隔时间,毫秒
            t.Interval = 1000;
            //设置是执行一次(false)还是一直执行(true);   
            t.AutoReset = true;
            //是否执行System.Timers.Timer.Elapsed事件; 
            t.Enabled = true;
            Console.Read();
        }
 
        private void theout(object source, System.Timers.ElapsedEventArgs e)
        {
            using(Ping ping1 = new Ping())    //将ping1放在此处可完美解决问题,3.5下有效,内存维持低位,且ping间隔可以很小
            {
                ping1.SendAsync("127.0.0.1", null);
            }
        }
    }
}
於黾 2015-02-09
  • 打赏
  • 举报
回复
既然同样的代码在不同的框架版本下运行出来效果不一样,说明底层实现也还是随着版本的升高有改进了 不要一味的纠结底层实现,更不要靠底层实现去给你"纠错",先把你的业务逻辑弄清楚,让它不要产生不可预料的问题,这样不管底层到底怎么实现的,都不会出大问题
54phoenix 2015-02-09
  • 打赏
  • 举报
回复
引用 11 楼 Z65443344 的回复:
你派5个人,他派5个人,每个人都派5个人,那不就越来越多了吗 而且因为派的人多了,他们在门卫那个小地方就会堵塞,导致更多的人在外面排队,进不去
程序里就一个timer每秒钟派一个人去啊,就极端情况考虑,一个一直都ping不通的IP,第1、2、3、4、5个人去都在那等,第6个人去的时候,第1个人因为超时就回来了,门卫那就剩2、3、4、5、6共五个人,第7个人去时第2个人也回来了,所以还是共5个人在门卫那,而且以后一直都是维持着五个人在等消息,不会出现越积越多的情况啊,不解。 也许C#实际不是仅仅这么简单的处理,可能底层还有其他东西在累积?
於黾 2015-02-09
  • 打赏
  • 举报
回复
你派5个人,他派5个人,每个人都派5个人,那不就越来越多了吗 而且因为派的人多了,他们在门卫那个小地方就会堵塞,导致更多的人在外面排队,进不去
54phoenix 2015-02-09
  • 打赏
  • 举报
回复
引用 9 楼 Z65443344 的回复:
[quote=引用 8 楼 qmye888 的回复:] [quote=引用 7 楼 Z65443344 的回复:] 逻辑问题 要么你上一次没ping通,不要进行下一次的ping 要么你将超时时间设置成1秒,而不是默认的4秒
这个问题已经比较明确了,确实就是这方面的问题,但需求就是想每秒ping一次,不知道3.5下面有没有好的方法,纠结[/quote] 那不是需求,而是拍脑袋想出来的方案 好比今天有快递要来,你就派个人不断的去门卫看是否来了快递 然后你说:需求就是每隔10分钟派个人过去,而不管前面派出的人是否还在那里根本没有走开? 前一次正在ping,没有超时,你另开个线程继续ping是没有任何意义的 就好比已经有个人在门卫等快递了,你再派一个人去看,该来还是会来,该不来还是不来,没有任何意义 所以,如果想避免门卫挤了一堆人在那等快递 1.要么写个异步回调方法,让门卫接到快递给你打电话,而不是你不断派人去看 2.要么前面的人没走之前,就不要再派其他人去 3.要么让前面的人看一眼,没有就赶紧回来,而不是一直在那等[/quote] 醍醐灌顶,多谢指点,去学一下异步回调。 不过我在想,其实如果就像放在方法内部,每次用新实例,也就是你说的一直派人去,但ping超时时间也就5秒钟,所以门卫那里最多会累计五个人在那等消息,而更早之前的肯定已经走了,感觉上应该不会越积越多啊,糊涂了糊涂了,初学者很多东西没概念,乱问,见谅见谅,呵呵。
於黾 2015-02-09
  • 打赏
  • 举报
回复
引用 8 楼 qmye888 的回复:
[quote=引用 7 楼 Z65443344 的回复:] 逻辑问题 要么你上一次没ping通,不要进行下一次的ping 要么你将超时时间设置成1秒,而不是默认的4秒
这个问题已经比较明确了,确实就是这方面的问题,但需求就是想每秒ping一次,不知道3.5下面有没有好的方法,纠结[/quote] 那不是需求,而是拍脑袋想出来的方案 好比今天有快递要来,你就派个人不断的去门卫看是否来了快递 然后你说:需求就是每隔10分钟派个人过去,而不管前面派出的人是否还在那里根本没有走开? 前一次正在ping,没有超时,你另开个线程继续ping是没有任何意义的 就好比已经有个人在门卫等快递了,你再派一个人去看,该来还是会来,该不来还是不来,没有任何意义 所以,如果想避免门卫挤了一堆人在那等快递 1.要么写个异步回调方法,让门卫接到快递给你打电话,而不是你不断派人去看 2.要么前面的人没走之前,就不要再派其他人去 3.要么让前面的人看一眼,没有就赶紧回来,而不是一直在那等
54phoenix 2015-02-09
  • 打赏
  • 举报
回复
引用 7 楼 Z65443344 的回复:
逻辑问题 要么你上一次没ping通,不要进行下一次的ping 要么你将超时时间设置成1秒,而不是默认的4秒
这个问题已经比较明确了,确实就是这方面的问题,但需求就是想每秒ping一次,不知道3.5下面有没有好的方法,纠结
於黾 2015-02-09
  • 打赏
  • 举报
回复
逻辑问题 要么你上一次没ping通,不要进行下一次的ping 要么你将超时时间设置成1秒,而不是默认的4秒
54phoenix 2015-02-09
  • 打赏
  • 举报
回复
引用 4 楼 SPFarm 的回复:
[quote=引用 2 楼 qmye888 的回复:] 怎么释放?局部变量不是自动回收的吗,方法内部的实例是否需要手动释放?请指教
局部变量是自动回收的,但是并不是马上就回收的,垃圾回收机制有一套算法来决定什么时候回收。因此局部变量不需要手动释放(仅限于托管代码)。 [/quote] 谢谢指教! 那3.5版本下面要每秒ping一次,丢包时程序不出错,内存也不无限增长的方案能指教一二不?
54phoenix 2015-02-09
  • 打赏
  • 举报
回复
引用 13 楼 Z65443344 的回复:
既然同样的代码在不同的框架版本下运行出来效果不一样,说明底层实现也还是随着版本的升高有改进了 不要一味的纠结底层实现,更不要靠底层实现去给你"纠错",先把你的业务逻辑弄清楚,让它不要产生不可预料的问题,这样不管底层到底怎么实现的,都不会出大问题
嗯,确实应该这样考虑,多谢了,讨论的差不多了,结贴!
devmiao 2015-02-08
  • 打赏
  • 举报
回复
就这样的程序,单单看内存使用看不出来什么,因为程序本身的内存增量太小了。
SPFarmer 2015-02-08
  • 打赏
  • 举报
回复
引用 2 楼 qmye888 的回复:
怎么释放?局部变量不是自动回收的吗,方法内部的实例是否需要手动释放?请指教
局部变量是自动回收的,但是并不是马上就回收的,垃圾回收机制有一套算法来决定什么时候回收。因此局部变量不需要手动释放(仅限于托管代码)。
SPFarmer 2015-02-08
  • 打赏
  • 举报
回复
Ping ping1 = new Ping(); 放在外面,整个程序只有一个实例,所以占用的内存不会增加。 放到里面,那么每ping一次,内存里就多了一个新的对象,这样内存会占的越来越多。至于为什么不同版本的framework表现不一样,可能底层垃圾回收机制改了吧。
Justin-Liu 2015-02-08
  • 打赏
  • 举报
回复
代码中需要释放的对象没有释放 但是不同的框架版本下效果不一样,也可能跟底层机制有关。
54phoenix 2015-02-08
  • 打赏
  • 举报
回复
怎么释放?局部变量不是自动回收的吗,方法内部的实例是否需要手动释放?请指教
内容概要:本文探讨了CUDA并行计算优化技巧在通信行业核心网中的应用,聚焦于DPI流量识别与编解码加速实践。文章系统阐述了数据包级并行处理、GPUDirect RDMA、零拷贝内存、原子操作优化、warp级聚合等关键技术,并通过五元组哈希流量统计算法的GPU实现案例,展示了如何利用CUDA大幅提升处理效率。代码层面突出哈希函数的SIMT友好设计、无锁并发哈希表构建、内存访问优化与工程化权衡,实现了单batch处理时延从80微秒降至5微秒以内,吞吐达200Gbps以上,显著优于传统CPU方案。最后展望了算网融合、AI原生网络与绿色低碳三大发展趋势。; 适合人群:具备CUDA编程基础、熟悉网络协议栈与高性能数据面开发的通信领域研发人员,尤其是从事核心网、用户面功能(如UPF)、DPI系统优化的工程师;也适用于关注GPU加速在通信信号处理中应用的技术人员。; 使用场景及目标:①提升核心网用户面流量处理性能,实现高吞吐低时延的DPI与流统计;②优化LDPC/Polar译码、TLS批量协商等计算密集型任务;③降低单位比特处理功耗,满足运营商“双碳”目标下的能效要求;④探索AI与传统通信处理融合的统一算力架构。; 阅读建议:学习时应重点关注哈希设计避免warp divergence、原子操作的合理使用、内存预分配与批处理策略,并结合实际网络流量特性进行实验调优;建议在支持GPUDirect RDMA的硬件平台上复现案例,深入理解GPU与智能网卡协同工作的全链路优化潜力。
已经博主授权,源码转载自 https://pan.quark.cn/s/a4b39357ea24 在C语言编程环境中,指针是一项极为关键的基础元素,它赋予程序直接接触并干预内存位置的能力。本文将细致研究三种核心指针类型:指针数组、数组指针以及二级指针。 我们首先需要掌握指针的基础知识。所谓指针,即变量的内存位置标记,当我们声明一个指针变量,比如`int *p`,实际上是在构建一个能够容纳整型变量地址的标记。借助`&`运算符,我们可以获取变量的内存位置,并将其分配给指针,例如`p = &i`。不仅如此,指针还能用于数组元素的访问,例如`a[i]`与`*(a + i)`效果相同,因为数组名称在C语言中被视作指向数组首元素的指针。 数组指针属于一种特殊的指针变量,其指向的是某个一维数组的首地址。以一个整型数组`int a[5]`为例,`int (*p)[5]`即表示一个数组指针,它能保存数组`a`的地址。当对数组指针执行解引用操作`*p`时,结果将是整个数组,而非数组的第一个元素。由此可见,`*p`与`a`等价,它们都指向数组的起始点。 指针数组则是一种数组,其构成元素均为指针。例如,`int *p[5]`定义了一个由五个整型指针构成的数组。此类变量能够储存多个地址,每个地址都可以关联到一个整型变量。借助下标操作,例如`p[i]`,我们可以访问并处理这些指针所指向的变量。 二级指针,亦称为多级指针,是一种指向指针的指针。比如,`int **pp`即是一个二级指针,它能储存一个指向`int *`类型变量的地址。二级指针常用于处理多维数组,尤其是二维数组。在二维数组中,第一层索引通常对应行,第二层索引对应列。假设有一个`int arr[3][4]`的二维数组,一个二级指针`int ...

111,129

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧