今年安卓开发中碰到的几个稀奇古怪的问题

原文链接:https://yq.aliyun.com/articles/687834

如果你也遇到了,请保持淡定~

1.SIGBUS和SIGSEGV

首先是这两个名词的说明:

  1. SIGBUS(Bus error)意味着指针所对应的地址是有效地址,但总线不能正常使用该指针。通常是未对齐的数据访问所致。

  2. SIGSEGV(Segment fault)意味着指针所对应的地址是无效地址,没有物理内存对应该地址。

有人一看,什么指针不指针的,对于大多数开发人员来说,不涉及NDK这方面的开发。所以可以想到的就是我们使用的so库。

我这里碰到的SIGBUS相关问题主要集中在集成的极光推送,在极光社区的这篇帖子和我的问题一样。我收集到的信息集中在CPU架构为arm64-v8a,android 5.x 的 OPPO R9MOPPO R7SMOPPO A59MOPPO A59S等OPPO手机。如下图:

问题起因是这样,为了瘦身我们的apk文件,我只添加了armeabi-v7a 架构的相关so文件。因为现在绝大部分的设备都已经是 armeabi-v7a 和 arm64-v8a,虽然我也可以使用armeabi,但是性能关系我最终只保留了armeabi-v7a 。

按道理arm64-v8a设备可以兼容arm64-v8aarmeabi-v7aarmeabi。但结果在oppo的这些手机上没有兼容,或者说更加的严格,导致了未对齐的数据访问。为什么这么说,因为后来有观察再升级极光的sdk后,发现这类问题有所下降。当然如果你直接添加上arm64-v8a,则不会有这个问题。

导致这个问题有多方面的因素,有我们使用的三方sdk的问题,也有手机问题。但在手机不可变的基础上,只能我们去解决,所以尽量不要通过这种方法瘦身APK。(实在不行可以用折中方案,保留armeabi-v7a 和 arm64-v8a)。

SIGSEGV问题排除掉架构兼容问题,相对于集中在5.0以下及机子。这块问题相对比较复杂,我碰到了这样一个问题:

搜索了一下相关问题,找到一篇解决方法:三星 Android 4.3 机型上 webview crash 问题

有兴趣的可以去看看,这里就不赘述了。导致这类问题的情况比较多,只能是经验积累,碰到一个解决一个。不涉及NDK这方面的开发人员,很难规避掉此类问题。

2.TimeoutException

这个问题真的“无法避免”。从buyly的统计看主要集中在oppo 5.0~6.0及个别华为5.0机型。好吧又是oppo手机,oppo真的是很严格,我都快成黑粉了。。。 (当然了7,8,9看来挺不错的)

反馈上来的远比截图看的多,我只取了截取了一小部分。新版本已经“解决了”这个问题,所以现在报上来的主要都是老版本。

bugly异常信息如下:

 

错误堆栈信息:

FinalizerWatchdogDaemon
java.util.concurrent.TimeoutException
android.os.BinderProxy.finalize() timed out after 120 seconds
android.os.BinderProxy.destroy(Native Method)
android.os.BinderProxy.finalize(Binder.java:547)
java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:214)
java.lang.Daemons$FinalizerDaemon.run(Daemons.java:193)
java.lang.Thread.run(Thread.java:818)

首先来说明一下发生问题的原因,在GC时,为了减少应用程序的停顿,会启动四个GC相关的守护线程。FinalizerWatchdogDaemon就是其中之一,它是用来监控FinalizerDaemon线程的执行。

FinalizerDaemon:析构守护线程。对于重写了成员函数finalize的对象,它们被GC决定回收时,并没有马上被回收,而是被放入到一个队列中,等待FinalizerDaemon守护线程去调用它们的成员函数finalize,然后再被回收。

一旦检测到执行成员函数finalize时超出一定的时间,那么就会退出VM。我们可以理解为GC超时了。这个时间默认为10s,我通过翻看oppo、 华为的Framework源码发现这个时间在部分机型被改为了120s和30s。

虽然时间加长了,但还是一样的超时了,具体在oppo手机上为何这么慢,暂时无法得知,但是可以肯定的是Finalizer对象过多导致的。知道了原因,所以要模拟这个问题也很简单了。也就是引用一个重写finalize方法的实例,同时这个finalize方法有耗时操作,这时我们手动GC就行了。刚好前几天,在我订阅的张绍文老师的《Android开发高手课中》,老师提到了这个问题,同时分享了一个模拟问题并解决问题的 Demo。有兴趣的可以试试。

那么解决问题的方法也就来了,我们可以在ApplicationattachBaseContext中调用(可以针对问题机型及系统版本去处理,不要矫枉过正):

        try {
            final Class clazz = Class.forName("java.lang.Daemons$FinalizerWatchdogDaemon");
            final Field field = clazz.getDeclaredField("INSTANCE");
            field.setAccessible(true);
            final Object watchdog = field.get(null);
            try {
                final Field thread = clazz.getSuperclass().getDeclaredField("thread");
                thread.setAccessible(true);
                thread.set(watchdog, null);
            } catch (final Throwable t) {
                Log.e(TAG, "stopWatchDog, set null occur error:" + t);

                t.printStackTrace();
                try {
                    // 直接调用stop方法,在Android 6.0之前会有线程安全问题
                    final Method method = clazz.getSuperclass().getDeclaredMethod("stop");
                    method.setAccessible(true);
                    method.invoke(watchdog);
                } catch (final Throwable e) {
                    Log.e(TAG, "stopWatchDog, stop occur error:" + t);
                    t.printStackTrace();
                }
            }
        } catch (final Throwable t) {
            Log.e(TAG, "stopWatchDog, get object occur error:" + t);
            t.printStackTrace();
        }

其实我是用的是stackoverflow这篇帖子中提供的方法:

public static void fix() {
    try {
        Class clazz = Class.forName("java.lang.Daemons$FinalizerWatchdogDaemon");

        Method method = clazz.getSuperclass().getDeclaredMethod("stop");
        method.setAccessible(true);

        Field field = clazz.getDeclaredField("INSTANCE");
        field.setAccessible(true);

        method.invoke(field.get(null));

    }
    catch (Throwable e) {
        e.printStackTrace();
    }
}

两种方法都是通过反射最终将FinalizerWatchdogDaemon中的thread置空,这样也就不会执行此线程,所以不会再有超时异常发生。推荐老师的方法,更加全面完善。因为在Android 6.0之前会有线程安全问题,如果直接调用stop方法,还是会有几率触发此异常。5.0源代码如下:

private static abstract class Daemon implements Runnable {

        private Thread thread;// 一种是直接置空thread

        public synchronized void start() {
            if (thread != null) {
                throw new IllegalStateException("already running");
            }
            thread = new Thread(ThreadGroup.systemThreadGroup, this, getClass().getSimpleName());
            thread.setDaemon(true);
            thread.start();
        }

        public abstract void run();

        protected synchronized boolean isRunning() {
            return thread != null;
        }

        public synchronized void interrupt() {
            if (thread == null) {
                throw new IllegalStateException("not running");
            }
            thread.interrupt();
        }

        public void stop() {
            Thread threadToStop;
            synchronized (this) {
                threadToStop = thread;
                thread = null; // 一种是通过调用stop置空thread
            }
            if (threadToStop == null) {
                throw new IllegalStateException("not running");
            }
            threadToStop.interrupt();
            while (true) {
                try {
                    threadToStop.join();
                    return;
                } catch (InterruptedException ignored) {
                }
            }
        }

        public synchronized StackTraceElement[] getStackTrace() {
            return thread != null ? thread.getStackTrace() : EmptyArray.STACK_TRACE_ELEMENT;
        }
    }

这个所谓的线程安全问题就在stop方法中的threadToStop.interrupt()。在6.0开始,这里变为了interrupt(threadToStop),而interrupt方法加了同步锁。

public synchronized void interrupt(Thread thread) {
     if (thread == null) {
         throw new IllegalStateException("not running");
     }
     thread.interrupt();       
}

虽然崩溃不会出现了,但是问题依然存在,可谓治标不治本。通过这个问题也提醒我们,尽量避免重写finalize方法,同时不要在其中有耗时操作。其实我们Android中的View都有实现finalize方法,那么减少View的创建就是一种解决方法。

强烈推荐阅读提升Android下内存的使用意识和排查能力再谈Finalizer对象–大型App中内存与性能的隐性杀手

3.SchedulerPoolFactory

前一阵在用Android Studio的内存分析工具检测App时,发现每隔一秒,都会新分配出20多个实例,跟踪了一下发现是RxJava2中的SchedulerPoolFactory创建的。

一般来说如果一个页面创建加载好后是不会再有新的内存分配,除非页面有动画、轮播图、EditText的光标闪动等页面变化。当然了在应用退到后台时,或者页面不可见时,我们会停止这些任务。保证不做这些无用的操作。然而我在后台时,这个线程池还在不断运行着,也就是说CPU在周期性负载,自然也会耗电。那么就要想办法优化一下了。

SchedulerPoolFactory 的作用是管理 ScheduledExecutorServices的创建并清除。

SchedulerPoolFactory 部分源码如下:

static void tryStart(boolean purgeEnabled) {
        if (purgeEnabled) {
            for (;;) { // 一个死循环
                ScheduledExecutorService curr = PURGE_THREAD.get();
                if (curr != null) {
                    return;
                }
                ScheduledExecutorService next = Executors.newScheduledThreadPool(1, new RxThreadFactory("RxSchedulerPurge"));
                if (PURGE_THREAD.compareAndSet(curr, next)) {

            // RxSchedulerPurge线程池,每隔1s清除一次
                    next.scheduleAtFixedRate(new ScheduledTask(), PURGE_PERIOD_SECONDS, PURGE_PERIOD_SECONDS, TimeUnit.SECONDS);

                    return;
                } else {
                    next.shutdownNow();
                }
            }
        }
    }

   static final class ScheduledTask implements Runnable {
        @Override
        public void run() {
            for (ScheduledThreadPoolExecutor e : new ArrayList<ScheduledThreadPoolExecutor>(POOLS.keySet())) {
                if (e.isShutdown()) {
                    POOLS.remove(e); 
                } else {
                    e.purge();//图中154行,purge方法可用于移除那些已被取消的Future。
                }
            }
        }
    }

我查了相关问题,在stackoverflow找到了此问题,同时也给RxJava提了Issue,得到了回复是可以使用:

 // 修改周期时间为一小时
 System.setProperty("rx2.purge-period-seconds", "3600");

当然你也可以关闭周期清除:

 System.setProperty("rx2.purge-enabled", false);

作用范围如下:

 static final class PurgeProperties {

        boolean purgeEnable;

        int purgePeriod;

        void load(Properties properties) {
            if (properties.containsKey(PURGE_ENABLED_KEY)) {
                purgeEnable = Boolean.parseBoolean(properties.getProperty(PURGE_ENABLED_KEY));
            } else {
                purgeEnable = true; // 默认是true
            }

            if (purgeEnable && properties.containsKey(PURGE_PERIOD_SECONDS_KEY)) {
                try {
                    // 可以修改周期时间
                    purgePeriod = Integer.parseInt(properties.getProperty(PURGE_PERIOD_SECONDS_KEY));
                } catch (NumberFormatException ex) {
                    purgePeriod = 1; // 默认是1s
                }
            } else {
                purgePeriod = 1; // 默认是1s
            }
        }
    }

1s的清除周期我觉得有点太频繁了,最终我决定将周期时长改为60s。最好在首次使用RxJava前修改,放到Application中最好。

4.其他

  • 适配8.0时注意Service的创建。否则会有IllegalStateException异常:
java.lang.IllegalStateException:Not allowed to start service Intent { xxx.MyService }: app is in background uid null

  • 有些手机(已知oppo)在手机储存空间不足时,当你应用退到后台时会自动清除cache下文件,所以如果你有重要数据存储,避免放在cache下,否则当你再次进入应用时,再次获取数据时会有空指针。例如有使用磁盘缓存 DiskLruCache 来存储数据。

现在加Android开发群;701740775,可免费领取一份最新Android高级架构技术体系大纲和视频资料,以及这些年年积累整理的所有面试资源笔记。加群请备注csdn领取xx资料

展开阅读全文

稀奇古怪问题!关于request

08-05

我在一个类中声明一个HttpServletRequest request属性;rn该类中包含setRequest(HttpServletRequest req)rn this.request=req;rnrn有个输出的方法 在里面用request.getParameter("属性名")获得到的值是NULLrn但是在setRequest中使用req.getParameter("属性名")就能获得到值;rnPS:2个属性名完全一样rnrn为什么会这样?rn期待解答rnrn我把代码帖出来 大家看看rn这个是那个调用定时器任务的servletrnpackage myServlet;rnrnimport java.io.IOException;rnimport java.io.PrintWriter;rnimport java.util.Timer;rnrnimport javax.servlet.ServletException;rnimport javax.servlet.http.HttpServlet;rnimport javax.servlet.http.HttpServletRequest;rnimport javax.servlet.http.HttpServletResponse;rnrnimport myClass.myTimerTask;rnrnpublic class ActionServlet extends HttpServlet rnrn /**rn * Constructor of the object.rn */rn public ActionServlet() rn super();rn rnrn /**rn * Destruction of the servlet. rn */rn public void destroy() rn super.destroy(); // Just puts "destroy" string in logrn // Put your code herern rnrn /**rn * The doGet method of the servlet. rn *rn * This method is called when a form has its tag value method equals to get.rn * rn * @param request the request send by the client to the serverrn * @param response the response send by the server to the clientrn * @throws ServletException if an error occurredrn * @throws IOException if an error occurredrn */rn public void doGet(HttpServletRequest request, HttpServletResponse response)rn throws ServletException, IOException rn String url=request.getParameter("url");rn String fid=request.getParameter("fid");rn String tid=request.getParameter("tid");rn int interval=Integer.parseInt(request.getParameter("interval"));rn String content=request.getParameter("content");rn String type=new String(request.getParameter("type").getBytes("ISO-8859-1"),"gbk");rn String forwardUrl=url+"?step=2&action=reply&editor=0&atc_attachment=none&fid="+fid+"&tid="+tid+"&atc_content="+content+"";rn Timer myTimer=new Timer(true);rn if(type.equals("开始"))rn myTimerTask test=new myTimerTask();rn test.setRequest(request);rn myTimer.schedule(test, 0, interval*1000);rn elsern myTimer.cancel(); rn rn rnrn /**rn * The doPost method of the servlet. rn *rn * This method is called when a form has its tag value method equals to post.rn * rn * @param request the request send by the client to the serverrn * @param response the response send by the server to the clientrn * @throws ServletException if an error occurredrn * @throws IOException if an error occurredrn */rn public void doPost(HttpServletRequest request, HttpServletResponse response)rn throws ServletException, IOException rnrn doGet(request,response);rn rnrn /**rn * Initialization of the servlet. rn *rn * @throws ServletException if an error occurern */rn public void init() throws ServletException rn // Put your code herern rnrnrnrnrn这个是那个继承TimerTask的类rnrnpackage myClass;rnrnimport java.io.IOException;rnimport java.util.TimerTask;rnrnimport javax.servlet.ServletException;rnimport javax.servlet.http.*;rnrnpublic class myTimerTask extends TimerTask rn HttpServletRequest request;rn HttpServletResponse response;rn String forwardUrl="";rn /*public myTimerTask(HttpServletRequest req,HttpServletResponse res,String str)rn request=req;rn response=res;rn forwardUrl=str;rn 使用构造方法也不可以rn */rn public void setRequest(HttpServletRequest req)rn System.out.println(req.getParameter("url"));rn// 用req就能获得里面的值rn request=req;rn// 在这里request输出的就是NULLrn System.out.println(request.getParameter("url"));rn rn public void run() rn try rn// 在这里用requset输出也是NULLrn System.out.println(request.getParameter("url"));rn //request.getRequestDispatcher(forwardUrl).forward(request, response);rn catch (Exception e) rn e.printStackTrace();rn rn rnrnrn 论坛

稀奇古怪的考试?

07-04

首先,感谢上次教训我的一些大虾们, 编译原理的作业,我自己做了, 连续奋战了近一周,写了六百多行,终于做完了.在这个过程中,我确实觉得,如果你热爱编程的话,其它的事情都显得不重要了. rn 今天,我是来为自己挂掉的一门考试课而来的,不知道,各位读过计算机专业(程序设计)的rn大哥们,在三下时有没有开过一门 叫做 信号与系统 的课.rn 而我作为一名计算机系大三的学生,我们居然在本学期开了,想来想去,不知道和程序设计有什么联系,一开始就抵制它,并且为 为什么不开c++而不满,但是想不到,后来 信号与系统 竟然要考试,于是乎,1号时,老师搞指导,我们都去听,搞了几个题目,老师说,只要搞会就没有问题了,又听说监考老师,十分的鸡婆,于是,抓紧最后几天,通宵奋战,搞会了那几题,而且考前去看了看考场,发现自己做最后一排,感觉很放心.rn 哪知道今天考试,首先,位置居然被人换了,成了第一个,老师指导的题目竟然一个也没有,rn 想到自己还可以做20-30分的计算题,收卷时还可以看看填空和选择题,应该还是没有问题的,于是,我就在那里忍着.rn 终于,考试结束了,刚准备行动,老师竟然说了句"大家都不要动!"rn 我心里一纳闷,"我动了,你还能把我怎样?",抬头一看,赫然看见黑板上一张表,表上把每个人的位置都画上去了,凡是动了的,表中对应位置都被划了个 叉叉.rn 考完后,我忍不住,大骂了一顿,从学校领导到换桌子的人渣.但是也没有办法,重修看来成为了必要.又要丢180元去喂狗了.rn rn 论坛

稀奇古怪问题,请大家帮忙

01-21

月报表窗体有一导出到EXCEL文件功能,此报表包含一fpSpread1控件rnPrivate Sub Command1_Click()rnrn Dim wenjian As Stringrn Dim bolP As Booleanrn rn CommonDialog1.InitDir = App.Pathrn CommonDialog1.DialogTitle = " 导出到EXCEL文件 "rn CommonDialog1.Filter = " 新建Excel文件|*.xls"rn CommonDialog1.ShowSavern rn wenjian = CommonDialog1.FileNamern rn Dim Temp As Variant, i As Longrn rn F = fpSpread1.ExportToExcel(CommonDialog1.FileName, "Sheet1", "")rn If F = False Thenrn MsgBox " 导出失败。 ", vbOKOnly, "提示"rn Exit Subrn End Ifrn rn bolP = funOpenExcelFile(xlsApp, xlsBook, xlsSheet, wenjian, "Sheet1", "", True)rn If bolP = False Thenrn MsgBox Chr(13) & " 操作失败。 ", vbOKOnly, FSrn Exit Subrn End IfrnrnEnd Subrnrn当选择的EXCEL文件保存目录不在本程序目录之中时,导出完EXCEL文件后,再打开窗体B时就会出现“无法启动应用程序。工作组信息丢失,或是已被其他用户以独占方式打开”的错误提示,提示的标题栏显示“ADOXQ”(这是这个窗体上一数据控件的名称)rn而该窗体中ADOXQ控件的CONNECTIONSTRING属性值为:rnProvider=Microsoft.Jet.OLEDB.4.0;Password=xxxxx;User ID=jia;Data Source=sj.mdb;Persist Security Info=True;Jet OLEDB:System database=e.mdw;Jet OLEDB:Database Password=xxxxxxrnrn但是如果打开月报表窗体,但不导出EXCEL文件,或即使导出EXCEL文件,但导出目录在本程序目录中时,之后再打开窗体B,就不会出现这个错误提示。rnrn请教大家是何原因,如何解决?rn 论坛

几个常碰到.NET问题的解决!

12-06

.NET中的字符串截取rn中英文的混合截取(一个中文等价于2个英文字符)rn/// rn /// 字符串截取rn /// rn /// 原始字符串rn /// 截取后的最大字符长度rn /// 字符串rn private string GetTrimString(string strSource,int iMaxCount)rn rn char[] c;rn byte[] b;rn string result;rn c=strSource.ToCharArray();rn b=System.Text.Encoding.Default.GetBytes(c);rn if(System.Text.Encoding.Default.GetByteCount(strSource) < iMaxCount)rn result=System.Text.Encoding.Default.GetString(b);rn elsern result=System.Text.Encoding.Default.GetString(b,0,iMaxCount);rn return result;rn rnjavascript客户端规定最多输入的字符串长度rn rnaspx中调用的代码:rnrnrn服务器端调用javascript方法rn一般的写法:Response.Write(“ ”);rn自然而然的写法:Response.Write(“ ”);rn但是这样写是错误的,因为这种写法生成的htm文档的开头为: ,由于这句话是第一句,而此时TextBox1对应的元素并没有形成,所以会出现错误。rn正确的写法:Page.RegisterStartupScript("ShowValue"," ");能够在加载完所有的元素后才执行rnrn制作弹出式的窗口(像MSN)rn rnrn屏蔽鼠标经过图片时候产生的菜单rn rnrn重新调整窗口的大小位置rnwindow.resizeBy(x,y);//在原来的基础上动态增加指定的宽度和高度rnfunction ResizeWindow() window.resizeTo(300,300); alert('resizedTo completed'); window.moveBy(100,100); alert('moveBy completed'); window.moveTo(200,200); alert('moveTo completed'); rnrn放大缩小整个网页rnjavascript函数rn rn页面设置rnrn然后放几个按钮就可以发达缩小了rnrn强制控制字符换行rnrnrn在web服务里传递 PostedFile保存到数据库里rnHttpPostedFile UpFile = UP_FILE.PostedFile;rnByte[] FileByteArray = new Byte[FileLength]; //图象文件临时储存Byte数组rnStream StreamObject = UpFile.InputStream; //建立数据流对像rn//读取文件数据,FileByteArray为数据储存体,0为数据指针位置、FileLnegth为数据长度rnStreamObject.Read(FileByteArray,0,FileLength);rn//建立数据的文档数据rnSqlParameter imageParameter = new System.Data.SqlClient.SqlParameter("@Data", SqlDbType.Image );rnimageParameter.Value = FileByteArray;rn//上传文件rnrn在DataGrid中确定当前行的所有字段都已经绑定完成了rnrnif(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.SelectedItem)rnrn …………………………….rnrnrn网页中使用Office的Web图表组件rnchartString.Append("");rnchartString.Append("");rnrn在Oracle中使用大对象数据类型Clobrn程序中的写法:ocomm.Parameters.Add(new OracleParameter("pContent",OracleType.Clob));rnOracle数据库中的字段类型为:Clob,注意:在OEM中查看的时候是看不到Clob字段的rn存储过程的写法:输入参数为:pContent in clobrnSql语句写法:和其他一样rn使用到的函数:to_char(lContent)---〉转换为字符串rnrn在vb6中调用web服务rnPrivate oSoap As New SoapClient30 'web服务对象rnoSoap.ClientProperty("ServerHTTPRequest") = TruernCall oSoap.MSSoapInit("http://" & s_WebServer & "/service/FileOperation/upload.asmx?WSDL")rn调用的时候只要在服务对象后面跟对应的方法就可以了,如:rnDim I as integerrnI=oSoap.Calc(100,200) ‘其中Calc是web服务的函数名称rn当然,在调用web服务的时候,一定要在编写web服务的时候注意到为了使vb6能够调用,一定要使用vb6支持的返回、输入类型rn最后,最终要的是要先安装软件:Soap3 SDK,而且在项目中引用对应的Soap Type3rnrn多项目之间共享 Sessionrn首先多个项目中必须有一个项目是其他几个项目的上级目录(虚拟目录 或者 网站);rn接着在所有的子项目文件夹的web.config中,删除两个节点:authentication和sessionState;rn然后是把所有子项目在IIS中取消虚拟目录的属性(变为普通文件夹)rn然后在上级项目中引用项目(所有要共享Session的项目)rn好了rnrnDataGrid导出Excel(不再服务器上保存,只是在客户端)rn函数:rn///rn///ctl为要导出的DataGridrn///dt为对应的数据源rn///rnpublic void DataGridToExcel(System.Web.UI.WebControls.DataGrid ctl,DataTable dt)rn rn DataView oView=new DataView(dt);rn ctl.DataSource=oView;rn ctl.DataBind();rn Response.ContentType = "application/vnd.ms-excel";rn Response.Charset = "";rn Page.EnableViewState= false;rn System.IO.StringWriter tw=new System.IO.StringWriter();rn System.Web.UI.HtmlTextWriter hw=new HtmlTextWriter(tw);rn ctl.RenderControl(hw);rn Response.Write(tw.ToString());rn Response.End();rn rn 论坛

碰到几个基础问题,请指教

11-08

1.我用database configuration assistant创建一个新的数据库的时候花了好长时间也没成功,进度总是停在58%的地方,系统提示正在添加oracle jserver,搞了好久rn也没添加好,硬盘在狂闪,我都有些气馁了,我装的是oracle 8.1.7.是不是机子配置不行啊?内存才128m。我开始安装oracle的时候系统也装了一个默认的数据库,但没用多久时间啊,请帮忙!!rn2.我用net8配置了一个服务名(test),连接本地的数据库,然后在dba studio里面创建了一个database links,在service里面指定为test,然后测试数据库链接,可是不通,是不是service里面填错了?还是怎么,请指导!rn3.在建立一个散列聚簇的时候,可以制定一个散列函数或者使用oracle内部的散列函数,但是怎么指定一个散列函数呢?oracle内部的散列函数又是什么呢?rn4.到底段和表的区别是什么?是不是一个表含有多个段?比如,一个表有数据段,在这个表上建立索引的话,还有索引段。一个数据段里面就只有一个表的数据还是可以有几个表的呢?rn5.登陆oracle数据库的时候,可以用internal直接登陆,不用密码,它相当于sys用户,我察看dba_users字典里面没有这个用户,我能不能控制,让用internal登陆时,必须输入密码?怎么设定呢?rn6.Create tablespace test datafile 'd:\orant\database\test.dbf'rn size 50k autoextend on next 10k maxsize unlimited rn default storage (initial 128k next 16k pctincrease 5 rn minextents 1 maxextents 50) online;rn这句话里面定义的数据文件为test.dbf,其大小初始为50kb,表空间的存储方案是初始128kb。这到底该怎么理解呢?表空间里面就一个数据文件test.dbf,但是数据文件的初始大小是50kb,而表空间的初始大小是128kb?两者为什么不同呢?是不是这个表空间自动创一个回滚段?大小为78kb?rn好多概念理解得不够透彻,希望大家帮帮我!先谢过了rn 论坛

学习过程碰到的几个C++的概念问题!

07-29

1>rnclass StringBadrnrnprivate:rnchar *str;rnint len;rnstatic int num_strings;rnpublic:rnStringBad (const char *s);rnStringBad();rn~StringBad();rnrnStringBad A ("clear up");rnStringBad B;rnB = A;rn现有:"赋值操作符"原型: StringBad & StringBad :perator= (const StringBad & );rn问题:当然我把A赋值给A,(B=A),根据原型它返回的是StringBad的引用,那么就是讲B中的数据与rnA中的数据是一个地址咯?那B这个对象与A对象不是共享了一些数据?这样不是很危险吗?rnrn2>rnStringBad & StringBad :: operator = ( const StringBad &)rnrnif (this == & st)rnreturn *this;rndelete [ ] str;rnlen = st.len;rnstr = new char [len+1];rnstrcpy (str,st.str);rnreturn *this;rnrn这是一个赋值过程.其中:delete [] str;目的是释放由于目标对象可能引用了以前分配的数据.rn我想问如果目标对象没有引用什么数据这一句将如何作用呢?delete不是只用于用new分配的rn内存吗?这个str不一定是由new分配的呀!rnrn3>rn对类数据成员的操作问题?rn比如一个成员函数对三个数据成员进行操作然后就直接改变了它们的值.rn我想不通为什么它这样对成员数据进行操作没有用返回,指针,引用,就可以直接更改了它们的值呢?rnrnEG:rnclass basernrnprivate:rnint a ;rndouble b;rnpublic:rnupdate (int x, double y);rnrnbase::updata (int x, double y)rnrna = x;rnb = y;rnrnrn这样a,b的值就直接被改变了,为什么呢? 论坛

没有更多推荐了,返回首页