none
画大量的线,内存占用太大怎么办 RRS feed

  • 问题

  • 我用canvas1.Children.Add(line);画了100万条线,内存就占用了1个G,用户不可接受啊,我画的PCB的线路,这里有Silverlight的高手吗,能不能用什么办法移到缓存什么的,或者有没有别的办法,拜托了,谢谢
    2009年8月7日 0:54

答案


  • 刚才我做了解100万条线的测试,我机器的环境是4G内存,cpu 2080 联想D420,在虚拟机上做的测试。机器在不调试状态下内存占用500M.

    1.测试一:把所有的线画在一个Canvas上
    内存占用超过1.36G以上。机器cpu 全部占完,100万条线画在同一个Canvas没有实验成功.

    2.测试二: 把图像绘制在 WriteableBitmap 上,
    绘制在 WriteableBitmap 上,然后当做图片再显示出来
    10万条可以实现.
    100万条实现不了

    3.测试三:把图像绘制在多个Canvas上,再把Canvas绘制出来 WriteableBitmap 上,
    100万条可以实现,分为10组,每画100000条(每画100000条线需要57秒)加入到WriteableBitmap 上。你在画的时候把优先级高的可以先画出来,其它的再异步画上去。如果用户需要放大某一部分的时候可以把那部分再单独画出来.


    <UserControl
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    	mc:Ignorable="d"
    	 xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
      xmlns:controlsToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
    
    	x:Class="SilverlightApplication2.UserControl1"
    	d:DesignWidth="640" d:DesignHeight="480">
    
        <StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" Margin="10">
    
            
            <Button x:Name="test" Width="100" Height="50" Click="btnTest_Click" />
            <!-- thumbnails go here -->
    
            <Grid x:Name="thumbs"  Margin="10,40,10,10">
            </Grid>
    
        </StackPanel>
    
    </UserControl>
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Windows.Media.Imaging;
    
    namespace SilverlightApplication2
    {
    	public partial class UserControl1 : UserControl
    	{
    		public UserControl1()
    		{
    			// Required to initialize variables
    			InitializeComponent();
    		}
    
            private void btnTest_Click(object sender, RoutedEventArgs e)
            {
                for (int i = 0; i < 10; i++)
                {
                    Canvas canvas = new Canvas();
                    canvas.Width = 600;
                    canvas.Height = 600;
    
                    Random rand = new Random();
    
                    for (int j = 0; j < 100000; j++)
                    {
                        double x = rand.NextDouble() * 500;
    
                        double y = rand.NextDouble() * 500;
                        Line line = new Line();
                        line.StrokeThickness = 1;
    
                        line.X1 = x;
                        line.Y1 = y;
                        line.Stroke = new SolidColorBrush(Colors.Blue);
                        canvas.Children.Add(line);
                    }
                    WriteableBitmap wb = new WriteableBitmap(canvas, null);
                    Image image = new Image();
                    image.Height = 600;
                    image.Margin = new Thickness(10);
                    image.Source = wb;
                    thumbs.Children.Add(image);
                }
    
            }
    
           
    	}
    }


    努力!写一个js解析器,一个svg插件,一个绘图程序,做好自己,呵呵~!
    2009年8月9日 10:00
    版主

全部回复

  • 我感觉SL就不是干这个用的 - -!

    2009年8月7日 3:47
  • 改用Path,这个画图比较合适,但总的来说Silverlight毕竟不是Protel。Path构造语法是:

    1. 移动指令:Move Command(M):M 起始点,或者:m 起始点
    比如:M 100,240 或 m 100,240
    使用大写M时,表示绝对值; 使用小写m时; 表示相对于前一点的值,如果前一点没有指定,则使用(0,0)。

    2. 绘制指令(Draw Command): 
    (1) 直线:Line(L)
    (2) 水平直线: Horizontal line(H)
    (3) 垂直直线: Vertical line(V)
    (4) 三次方程式贝塞尔曲线: Cubic Bezier curve(C)
    (5) 二次方程式贝塞尔曲线: Quadratic Bezier curve(Q)
    (6) 平滑三次方程式贝塞尔曲线: Smooth cubic Bezier curve(S)
    (7) 平滑二次方程式贝塞尔曲线: smooth quadratic Bezier curve(T)
    (8) 椭圆圆弧: elliptical Arc(A)

    上面每种形状后用括号括起的英文字母为命令简写的大写形式,但你也可以使用小写。使用大写与小写的区别是:大写是绝对值,小写是相对值。重复使用同一种类型时,就可以省略前面的命令。比如:L 100,200 L 300,400简写为:L 100,200 300,400。

    绘制指令格式语法:

    (1) 直线:Line(L)
    格式:L 结束点坐标 或: l 结束点坐标。
    比如:L 100,100 或 l 100 100。坐标值可以使用x,y(中间用英文逗号隔开)或x y(中间用半角空格隔开)的形式。

    (2) 水平直线  Horizontal line(H):绘制从当前点到指定x坐标的直线。
    格式:H x值 或 h x值(x为System.Double类型的值)
    比如:H 100或h 100,也可以是:H 100.00或h 100.00等形式。

    (3) 垂直直线 Vertical line(V):绘制从当前点到指定y坐标的直线。
    格式:V y值 或 v y值(y为System.Double类型的值)
    比如:V 100或y 100,也可以是:V 100.00或v 100.00等形式。

    (4) 三次方程式贝塞尔曲线 Cubic Bezier curve(C):通过指定两个控制点来绘制由当前点到指定结束点间的三次方程贝塞尔曲线。
    格式:C 第一控制点 第二控制点 结束点 或 c 第一控制点 第二控制点 结束点
    比如:C 100,200 200,400 300,200 或 c 100,200 200,400 300,200
    其中,点(100,200)为第一控制点,点(200,400)为第二控制点,点(300,200)为结束点。

    (5) 二次方程式贝塞尔曲线 Quadratic Bezier curve(Q):通过指定的一个控制点来绘制由当前点到指定结束点间的二次方程贝塞尔曲线。
    格式:Q 控制点 结束点 或 q 控制点 结束点
    比如:q 100,200 300,200。其中,点(100,200)为控制点,点(300,200)为结束点。

    (6) 平滑三次方程式贝塞尔曲线: Smooth cubic Bezier curve(S):通过一个指定点来“平滑地”控制当前点到指定点的贝塞尔曲线。
    格式:S 控制点 结束点 或 s 控制点 结束点
    比如:S 100,200 200,300

    (7) 平滑二次方程式贝塞尔曲线 smooth quadratic Bezier curve(T):与平滑三次方程贝塞尔曲线类似。
    格式:T 控制点 结束点 或 t 控制点 结束点
    比如:T 100,200 200,300

    (8) 椭圆圆弧: elliptical Arc(A) : 在当前点与指定结束点间绘制圆弧。
    A 尺寸 圆弧旋转角度值 优势弧的标记 正负角度标记 结束点 或: a 尺寸 圆弧旋转角度值 优势弧的标记 正负角度标记 结束点
    尺寸(Size): System.Windows.Size类型,指定椭圆圆弧X,Y方向上的半径值。
    旋转角度(rotationAngle):System.Double类型。
    圆弧旋转角度值(rotationAngle):椭圆弧的旋转角度值。
    优势弧的标记(isLargeArcFlag):是否为优势弧,如果弧的角度大于等于180度,则设为1,否则为0。
    正负角度标记(sweepDirectionFlag):当正角方向绘制时设为1,否则为0。
    结束点(endPoint):System.Windows.Point类型。
    比如:A 5,5 0 0 1 10,10

    3. 关闭指令(close Command):用以将图形的首、尾点用直线连接,以形成一个封闭的区域。
    用Z或z表示。

    F0 指定 EvenOdd 填充规则。
    F1 指定 Nonzero 填充规则。
    如果省略此命令,则路径使用默认行为,即 EvenOdd。如果指定此命令,则必须将其置于最前面。
    EvenOdd 确定一个点是否位于填充区域内的规则,具体方法是从该点沿任意方向画一条无限长的射线,然后计算该射线在给定形状中因交叉而形成的路径段数。如果该数为奇数,则点在内部;如果为偶数,则点在外部。 
    Nonzero 确定一个点是否位于路径填充区域内的规则,具体方法是从该点沿任意方向画一条无限长的射线,然后检查形状段与该射线的交点。从 0 开始计数,每当线段从左向右穿过该射线时加 1,而每当路径段从右向左穿过该射线时减 1。计算交点的数目后,如果结果为 0,则说明该点位于路径外部。否则,它位于路径内部。
    2009年8月7日 4:48
  • 没有必要所有的线段都画成path类型,对于不需要进行动画处理的线段可以搞成png格式的文件。你可以试试
    2009年8月8日 2:22
  • 还是在一个图片里面画,然后显示图片吧~

    理解的越多,需要记忆的就越少
    2009年8月8日 5:20
    版主

  • 刚才我做了解100万条线的测试,我机器的环境是4G内存,cpu 2080 联想D420,在虚拟机上做的测试。机器在不调试状态下内存占用500M.

    1.测试一:把所有的线画在一个Canvas上
    内存占用超过1.36G以上。机器cpu 全部占完,100万条线画在同一个Canvas没有实验成功.

    2.测试二: 把图像绘制在 WriteableBitmap 上,
    绘制在 WriteableBitmap 上,然后当做图片再显示出来
    10万条可以实现.
    100万条实现不了

    3.测试三:把图像绘制在多个Canvas上,再把Canvas绘制出来 WriteableBitmap 上,
    100万条可以实现,分为10组,每画100000条(每画100000条线需要57秒)加入到WriteableBitmap 上。你在画的时候把优先级高的可以先画出来,其它的再异步画上去。如果用户需要放大某一部分的时候可以把那部分再单独画出来.


    <UserControl
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    	mc:Ignorable="d"
    	 xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
      xmlns:controlsToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
    
    	x:Class="SilverlightApplication2.UserControl1"
    	d:DesignWidth="640" d:DesignHeight="480">
    
        <StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" Margin="10">
    
            
            <Button x:Name="test" Width="100" Height="50" Click="btnTest_Click" />
            <!-- thumbnails go here -->
    
            <Grid x:Name="thumbs"  Margin="10,40,10,10">
            </Grid>
    
        </StackPanel>
    
    </UserControl>
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Windows.Media.Imaging;
    
    namespace SilverlightApplication2
    {
    	public partial class UserControl1 : UserControl
    	{
    		public UserControl1()
    		{
    			// Required to initialize variables
    			InitializeComponent();
    		}
    
            private void btnTest_Click(object sender, RoutedEventArgs e)
            {
                for (int i = 0; i < 10; i++)
                {
                    Canvas canvas = new Canvas();
                    canvas.Width = 600;
                    canvas.Height = 600;
    
                    Random rand = new Random();
    
                    for (int j = 0; j < 100000; j++)
                    {
                        double x = rand.NextDouble() * 500;
    
                        double y = rand.NextDouble() * 500;
                        Line line = new Line();
                        line.StrokeThickness = 1;
    
                        line.X1 = x;
                        line.Y1 = y;
                        line.Stroke = new SolidColorBrush(Colors.Blue);
                        canvas.Children.Add(line);
                    }
                    WriteableBitmap wb = new WriteableBitmap(canvas, null);
                    Image image = new Image();
                    image.Height = 600;
                    image.Margin = new Thickness(10);
                    image.Source = wb;
                    thumbs.Children.Add(image);
                }
    
            }
    
           
    	}
    }


    努力!写一个js解析器,一个svg插件,一个绘图程序,做好自己,呵呵~!
    2009年8月9日 10:00
    版主
  • 图片测试图片地址:






    我想如果你画很多电路的话,你可能需要把电路分配在不同的Canvas上,做为不同的组.在拖动电路和绘制时才不会卡住。
    我在做游戏的时候,主角和其它场景也都是分解在不同的层上,否则在拖动地图的时候如果场景元素过多,就无法刷新
    努力!写一个js解析器,一个svg插件,一个绘图程序,做好自己,呵呵~!
    2009年8月9日 10:08
    版主
  • 如果你不把100万条线分组,在拖动的时候就。。。卡死。。^_^.

    努力!写一个js解析器,一个svg插件,一个绘图程序,做好自己,呵呵~!
    2009年8月9日 10:18
    版主