在运行tomcat后台运行时出现下面的问题是怎么回事

求大侠们帮忙!
tomcat 闹的百般故障....几个小时,就挂一次, 一天或者几天,甚至把机器拖死...
tomcat 5.5& ,连接池c3p0
mysql& 5.0 ,linux 系统,8G内存。
设置了最大文件数字" fs.file-max = 65535"
以下是catalina.out 里的几种报错~& 很全面的全错.....
linux系统日志查不到特别的信息,mysql里也米有
1st error :
------------------------------------------------------------------------------------------------------------------------------
2:06:12 org.apache.tomcat.util.net.PoolTcpEndpoint acceptSocket
严重: Endpoint ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=8080] ignored exception: java.net.SocketException: Too many open f
java.net.SocketException: Too many open files
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384)
at java.net.ServerSocket.implAccept(ServerSocket.java:450)
at java.net.ServerSocket.accept(ServerSocket.java:421)
at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:60)
at org.apache.tomcat.util.net.PoolTcpEndpoint.acceptSocket(PoolTcpEndpoint.java:407)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:70)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Thread.java:595)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
2:06:41 org.apache.catalina.loader.WebappClassLoader openJARs
警告: Failed to open JAR
java.util.zip.ZipException: Too many open files
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.&init&(ZipFile.java:203)
at java.util.jar.JarFile.&init&(JarFile.java:132)
at java.util.jar.JarFile.&init&(JarFile.java:97)
at org.apache.catalina.loader.WebappClassLoader.openJARs(WebappClassLoader.java:1544)
at org.apache.catalina.loader.WebappClassLoader.findResourceInternal(WebappClassLoader.java:1763)
at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1570)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:850)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1299)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1181)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
at org.apache.struts2.dispatcher.Dispatcher.cleanup(Dispatcher.java:254)
at org.apache.struts2.dispatcher.FilterDispatcher.destroy(FilterDispatcher.java:233)
at org.apache.catalina.core.ApplicationFilterConfig.release(ApplicationFilterConfig.java:258)
at org.apache.catalina.core.StandardContext.filterStop(StandardContext.java:3575)
at org.apache.catalina.core.StandardContext.stop(StandardContext.java:4249)
at org.apache.catalina.core.StandardContext.reload(StandardContext.java:2924)
at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:403)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1276)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1568)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1577)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1577)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1557)
at java.lang.Thread.run(Thread.java:595)
-------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------
09:33:10 [Timer-4] WARN com.mchange.v2.async.ThreadPoolAsynchronousRunner --& com.mchange.v2.async.ThreadPoolAsynchronou
sRunner$DeadlockDetector@1796149 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
09:33:12 [http-8080-Processor64] WARN com.mchange.v2.c3p0.impl.DefaultConnectionTester --& SQL State '08007' of Exceptio
n tested by statusOnException() implies that the database is invalid, and the pool should refill itself with fresh Connections.
com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: Communications link failure during commit(). Transaction resolution
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
at com.mysql.mit(ConnectionImpl.java:1569)
----------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------
at java.lang.Thread.run(Thread.java:595)
09:33:12 [http-8080-Processor65] WARN com.mchange.v2.c3p0.impl.DefaultConnectionTester --& SQL State '08007' of Exceptio
n tested by statusOnException() implies that the database is invalid, and the pool should refill itself with fresh Connections.
com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: Communications link failure during commit(). Transaction resolution
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
at com.mysql.mit(ConnectionImpl.java:1569)
at com.mchange.v2.c3p0.mit(NewProxyConnection.java:803)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DataSourceTransactionManager.java:262)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManag
er.java:732)
at org.springframework.transaction.mit(AbstractPlatformTransactionManager.java
at org.springframework.transaction.mitTransactionAfterReturning(TransactionAspectSup
port.java:321)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy5.getAllSearchRolesNumByCondition(Unknown Source)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
采纳的答案
看下代码里面 对 mysql 连接池有没有没有release的地方。。
明显socket 句柄没有得到释放。。
.ThreadPoolAsynchronou
sRunner$DeadlockDetector@1796149 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
明显有deadlock database 的地方。。
在Linux中,很多东西都是以文件句柄方式存在的,比如文件,Socket等,
从现象和异常来看,应该是Socket,文件或数据库连接等使用未正确关闭,导致过多的文件句柄被打开
Too many open files 问题
你操作文本记得要关闭。否则,你把文件数量设置到N大都没用。
我也是前天遇到这样的问题,操作3W多个文件,忘记关闭了,老给我提示too many open files。希望对你有帮助
已解决问题
未解决问题用的SSH框架,工程可以跑起来,但是在用户登录的时候会出现这样的异常:
Unable to instantiate Action, org.itec.tvecm.web.action.UserAction,& defined for 'user' in namespace '/'Error creating bean with name 'org.itec.tvecm.web.action.UserAction':
Autowir nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private org.itec.tvecm.service.UserService org.itec.tvecm.web.action.UserAction.userS nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.itec.tvecm.service.UserService] is defined: Unsatisfied dependency of type [interface org.itec.tvecm.service.UserService]: expected at least 1 matching bean
com.opensymphony.xwork2.DefaultActionInvocation.createAction(DefaultActionInvocation.java:306)
com.opensymphony.xwork2.DefaultActionInvocation.init(DefaultActionInvocation.java:387)
com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:186)
&&&&&&& ... ...
主要问题是感觉userService没有被注入到UserAction中,但是在UserAction中已经写了注解,而且spring的配置文件中也使用了
&context:component-scan base-package="*****" /&路径都没有问题,请问高手,到底是神马原因导致注入不成功呢?
问题补充:enet_java 写道JBOSS版本是哪个呀?是不是不支持注解式的注入方式。先确认一下
是jboss-5.1.0.GA,应该是支持注解的吧
问题补充:enet_java 写道引用Autowir nested exception is org.springframework.beans.factory.BeanCreationException
JBoss内核也是使用tomcat,关键还是看看tomcat的版本,看这句话的意思使用@Autowired 失败了。
是啊,我也觉得是service没有注入进去,我换过@Resource,还是没用。我用的是tomcat6.0.18,tomcat应该没问题吧。还可能是什么问题啊,搞不明白,谢谢给分析一下啊
问题补充:enet_java 写道你的这个工程可以再tomcat 6.0.18下面正常运行起来?
JBoss启动时初始化的jar文件是不是没有加载上呢,可以从这里看看。
嗯啊,在tomcat和jboss下都能跑起来,不会报错误信息,还需要额外加jar文件吗?用的都是在tomcat下的jar文件,都加在里面,没问题
问题补充:enet_java 写道Jboss初始化时,会从自己的lib库中加载jar文件,我怀疑这个时候还没有开始加载应用的lib库,但是已经初始化应用的一些配置文件了,这样启动的时候就已经抛出异常了,你可以看看jboss的日志,能否得到一些提示。
我不太明白您所说的意思,后台没有报出任何异常啊,而且主页也是可以访问到的,就是在用AJAX向后台发送登录信息的时候用FireFox看到了我刚开始所说的那些异常,能加我QQ吗,想向您详细请教一下可以吗?这个还有点急,我的qq:
问题补充:enet_java 写道能不能确定applicationContext.xml这个配置文件被加载了吗?
tomcat下面 使用的时候会不会报这种错误。
我在配置注解方式的时候还在
applicationContext.xml 配置了 &context:annotation-config /&。
应该是能加载的,应该刚开始的时候在web.xml中是这样:
&&&&&&& &context-param&
&param-name&contextConfigLocation&/param-name&
&param-value&classpath*:**/*Context.xml&/param-value&
&/context-param&
启动的时候后台没有报错,但是项目的主页是显示不出来的,报了一个找不到sessionFactory的异常,后来我把param-value改成
&param-value&/WEB-INF/*Context.xml&/param-value&
把applicationContext.xml放在WEB-INF下,就可以正常显示主页了。
我试过加&context:annotation-config /&,没有用。
问题补充:enet_java 写道你的action是不是通过spring来进行管理的?有没有加载配置文件?
action类上没有写@Component或者@Controller之类的,在tomcat下可以,难道到jboss下就不一样了?没有加配置文件,需要什么配置文件吗?
问题补充:enet_java 写道你的action是不是通过spring来进行管理的?有没有加载配置文件?
问题已经解决了,原来是spring2.*版本的一个bug,我把升级spring到3.0.5就没有这个问题了,郁闷,搞了n久,原来是spring的bug。
你的action是不是通过spring来进行管理的?有没有加载配置文件?
能不能确定applicationContext.xml这个配置文件被加载了吗?
tomcat下面 使用的时候会不会报这种错误。
我在配置注解方式的时候还在
applicationContext.xml 配置了 &context:annotation-config /&。
Jboss初始化时,会从自己的lib库中加载jar文件,我怀疑这个时候还没有开始加载应用的lib库,但是已经初始化应用的一些配置文件了,这样启动的时候就已经抛出异常了,你可以看看jboss的日志,能否得到一些提示。
你的这个工程可以再tomcat 6.0.18下面正常运行起来?
JBoss启动时初始化的jar文件是不是没有加载上呢,可以从这里看看。
引用Autowir nested exception is org.springframework.beans.factory.BeanCreationException
JBoss内核也是使用tomcat,关键还是看看tomcat的版本,看这句话的意思使用@Autowired 失败了。
JBOSS版本是哪个呀?是不是不支持注解式的注入方式。先确认一下
已解决问题
未解决问题Tomcat7下运行JSP找不到JSTL路径有关问题(无法解析EL)_【向ZangXT等大侠提问】关于创建String新对象有关问题的8种情况_内联的成员函数定义在.cpp文件中就不能铺展么__脚本百事通
稍等,加载中……
^_^请注意,有可能下面的2篇文章才是您想要的内容:
Tomcat7下运行JSP找不到JSTL路径有关问题(无法解析EL)
【向ZangXT等大侠提问】关于创建String新对象有关问题的8种情况
内联的成员函数定义在.cpp文件中就不能铺展么
Tomcat7下运行JSP找不到JSTL路径有关问题(无法解析EL)
Tomcat7下运行JSP找不到JSTL路径问题(无法解析EL)
之前在Tomcat7.0.37部署JAVA工程时,启动后运行JSP页面(页面中使用了EL)一直报如下错误:The absolute uri: /jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application该应用部署在tomcat6下时没有任何问题,就改到tomcat7时出现,网上查资料,有说是JSTL版本问题,也有说JSTL和Standard的JAR包冲突,都没能解决问题,后来看到帖子说把Standard包中的tld文件解压出来放到WEB-INF文件夹下,一试成功!总结:把Standard包中的tld文件(c.tld)解压出来放到WEB-INF文件夹下即解决问题。原贴地址:.cn/s/blog_6fwk4t.html
【向ZangXT等大侠提问】关于创建String新对象有关问题的8种情况
【向ZangXT等大侠提问】关于创建String新对象问题的8种情况仔细阅读了以往ZangXT大侠关于这个问题的几个回复,总结了8种情况,不知理解是否正确,恳请ZangXT大侠指正:1. String str1 = "abc";
System.out.println(str1 == "abc");步骤:1) 棧中开辟一块空间存放引用str1,2) String池中开辟一块空间,存放String常量"abc",3) 引用str1指向池中String常量"abc",4) str1所指代的地址即常量"abc"所在地址,输出为true2. String str2 = new String("abc");
System.out.println(str2 == "abc");步骤:1) 棧中开辟一块空间存放引用str2,2) 堆中开辟一块空间存放一个新建的String对象"abc",3) 引用str2指向堆中的新建的String对象"abc",4) str2所指代的对象地址为堆中地址,而常量"abc"地址在池中,输出为false3. String str3 = new String("abc");
System.out.println(str3 == str2);步骤:1) 棧中开辟一块空间存放引用str3,2) 堆中开辟一块新空间存放另外一个(不同于str2所指)新建的String对象,3) 引用str3指向另外新建的那个String对象4) str3和str2指向堆中不同的String对象,地址也不相同,输出为false4. String str4 = "a" + "b";
System.out.println(str4 == "ab");
步骤:1) 棧中开辟一块空间存放引用str4,2) 根据编译器合并已知量的优化功能,池中开辟一块空间,存放合并后的String常量"ab",3) 引用str4指向池中常量"ab",4) str4所指即池中常量"ab",输出为true5. final String s = "a";
String str5 = s + "b";
System.out.println(str5 == "ab");步骤:同46. String s1 = "a";
String s2 = "b";
String str6 = s1 + s2;
System.out.println(str6 == "ab");步骤:1) 棧中开辟一块中间存放引用s1,s1指向池中String常量"a",2) 棧中开辟一块中间存放引用s2,s2指向池中String常量"b",3) 棧中开辟一块中间存放引用str5,4) s1 + s2通过StringBuilder的最后一步toString()方法还原一个新的String对象"ab",因此堆中开辟一块空间存放此对象,5) 引用str6指向堆中(s1 + s2)所还原的新String对象,6) str6指向的对象在堆中,而常量"ab"在池中,输出为false7. String str7 = "abc".substring(0, 2);
步骤:1) 棧中开辟一块空间存放引用str7,2) substring()方法还原一个新的String对象"ab"(不同于str6所指),堆中开辟一块空间存放此对象,3) 引用str7指向堆中的新String对象,8. String str8 = "abc".toUpperCase();
步骤:1) 棧中开辟一块空间存放引用str6,2) toUpperCase()方法还原一个新的String对象"ABC",池中并未开辟新的空间存放String常量"ABC",3) 引用str8指向堆中的新String对象------解决方案--------------------我感觉是正确的.
------解决方案--------------------其实你的理解还是有些问题的。不是说你对字符串的理解,而是说你对对象的理解。你的这句话 -- 存放String常量"abc",
就是有问题的。一个String对象有3个重要的成员Java code
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
/** The count is the number of characters in the String. */
------解决方案--------------------
String s1="abc"; String s2=new String("abc"); 但假设我们能(我是说“假设能”)s1.value==s2.value,那么结果肯定是true,也就是s1和s2里面的value都指向了同一个字符串数组。
------解决方案--------------------
String s1 = "a"; String s2 = "b"; String str6 = s1 + s2; s1和s2都用的是常量池中的String对象,所以没有在堆中建立新对象。 而str6,除了在堆中new了一个String对象,其实还new了一个char数组,这个字符数组的长度就是2,放的是'a'和'b'。 而str6.value指向的是这个char[],而不是常量池里面的那个char[]。
------解决方案--------------------
当我们执行String s2=new String("abc"); 时候 在栈里应该分配一个空间,这个空间是这个构造方法的String original(original的引用)
这个引用就跟string original="abc";效果一样 这个时候看构造方法中的代码就行了. 因此我说:而s2是由本身对象value[]这个引用指向另一个数组对象。 ------解决方案--------------------先谢谢您!确实有道理,这么看来常量池中只有一个"abc",都会被引用和数组的value指向。但是:
String s1 = "a"; String s2 = "b"; String str6 = s1 + s2; s1和s2都用的是常量池中的String对象,所以没有在堆中建立新对象。 而str6,除了在堆中new了一个String对象,其实还new了一个char数组,这个字符数组的长度就是2,放的是'a'和'b'。 而str6.value指向的是这个char[],而不是常量池里面的那个char[]。
------解决方案--------------------楼上是错误的,常量池中是不会出现s1+s2的值的。这种问题别深究下去了。有兴趣自己看一下jvm规范/docs/books/jvms/
------解决方案--------------------不是说在常量池中有一个s1+s2的值,再由str6.value指向常量池中的这个s1+s2吗?答:常量池里面没有s1+s2的值,因为编译器无法判定s1或者s2会不会变。除非你把它们都申明为final,编译器才敢确定a+b的值,出现你说的情况。但是即使使用final,也并非你说的“str6.value指向常量池中的这个s1+s2吗”,String对象是不能+的,这个+号被理解为字符串相连。因此如果使用final,常量池里面应该有3个字符数组:['a'],['b'],['a','b'],str6的value是指向第3个的。
------解决方案--------------------非常感谢ZangXT 提出的意见,我看完基础会去看的~非常感谢您!hbwhwang ,我再最后最后最后问一个问题,这个问题搞明白就不研究string了。您说:
而str6,除了在堆中new了一个String对象,其实还new了一个char数组,这个字符数组的长度就是2,放的是'a'和'b'。
这里能不能解释清楚一下?或者您能不能解释一下,String str6 = s1 + s2; 在内存中的执行过程。我只是这点糊涂..其他情况,我想我已经都掌握了。或许您可以提供我一些资料,我自己查阅。google并没有找到类似的问题。
内联的成员函数定义在.cpp文件中就不能铺展么
内联的成员函数定义在.cpp文件中就不能展开么?同事说内联函数如果想展开就要一定定义在头文件中,不能定义在.cpp里。说是因为“内联时必须已经有了函数体才能做代码展开,如果函数定义在其它.cpp文件中编译的时候函数定义的代码就在其它obj文件里了,也就无法展开。”这么说对么?他还说“就算链接器有这么智能,能取其它OBJ里面取代码来内联,那么当只存在lib和dll没有obj文件的时候也是不能内联的”。请问他说的对吗?
网上看到很多关于内联的讹传,有的甚至被大家认为是法则,比如“内联函数里不能有循环,有了就不能展开”什么的,所以希望大家能拿出真凭实据,比如可以引用C++标准的文档,或者用某些代码来实验。
------解决方案--------------------C++的标准行为需要
1.inline写在定义上而不是声明上
2.inline函数写头文件而不是源文件
但目前大多数编主流译器,都是可以将cpp文件内的函数展开的,只要你是从源码编译的,能找到源码实现就行
对于二进制连接时的优化展开(将obj、lib中的函数内联展开,dll中目前还没有谁能做到),属于链接时优化,目前还远不如编译时优化成熟,但VC、icc也都是能做的(gcc不确定,没研究过)
编译器发展到今天,inline关键字已经退居二线,类似于register关键字,绝大部分情况下并没有一定得用的必要,本身inline和register都属于“建议而非强制”、“性能相关而非功能相关”,他们所做的事情本就不应该有程序员干预,而应该是编译器优化做的事情,换句话说inline和register是在编译器不够智能的时代的人为干预优化。目前的主流编译器,可以做到即便你不写inline,适合内联的函数也会内联,正如你不写register,编译器也会尽量使用寄存器而非堆栈一样的道理------解决方案--------------------+1 inline只是建议,至于实不实现是编译器的事
C++的标准行为需要
1.inline写在定义上而不是声明上
2.inline函数写头文件而不是源文件
但目前大多数编主流译器,都是可以将cpp文件内的函数展开的,只要你是从源码编译的,能找到源码实现就行
对于二进制连接时的优化展开(将obj、lib中的函数内联展开,dll中目前还没有谁能做到),属于链接时优化,目前还远不如编译时优化成熟,但VC、icc也都是能做的(gcc不……
------解决方案--------------------
综上, 循环可以展开内联, 内联可以放在.h中 类结束后实现。 内联不能放在cpp中实现, 否则编译通过,连接失败
的确写上inline的话会造成链接失败。
cpp中的函数不能加上inline,但编译器会依据某些标准,内联其他cpp中实现的函数。
确实如此,我的错误------解决方案--------------------c++标准N1905中:Every program shall contain exactly one definition of every non-inline function or object that is
diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined
library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in
every translation unit in which it is used.
最好一句讲的很清楚。 但是inline的函数定义可以放在cpp中,只是其它编译单元无法使用这个函数,仅限在cpp内部使用。 放在头文件中的inline函数,可以再不同的cpp中使用(或展开)------解决方案--------------------
intel C++ 编译器
编译器参数inline-forceinline
Specifies that an inline routine should be inlined whenever the compiler can do so.
Because C++ member functions whose definitions are included in the class declaration are considered inline functions by default, using this option will also make these member functions "forceinline" functions.
When you use this option to change the meaning of inline to "forceinline", the compiler may do so much additional inlining that it runs out of memory and terminates with an "out of memory" message.
finline-limit
inline-max-per-compile------解决方案--------------------去看herb sutter 的《exceptional c++》系列,大概一共3论Inline
其中有足够解答楼主的信息。
herb sutter的话,可比我们这些混混权威多了。
这个问题,即使是扣标准也是解答不了的。------解决方案--------------------其实我觉得标准说的挺清楚的,c++11 3.2/3 说
An inline function shall be defined in every translation unit in which it is odr-used.
所以 inline function 必然只能定义在头文件里面,因为这样才能够通过 #include 将其定义,而非仅仅是声明,包含进目标 translation unit 里面。非得写在 cpp 里面也行,但是就得像 #29 说的,#include 该 cpp 文件了,不过这样用 cpp 的话,本质上也就是将其用作 .h 文件了。#18 的例子程序中因为 main.cpp 只包含了 test.h,所以在 main 里面只能看到 test::fun 的声明,而看不见定义,因此会导致链接错误,此例子展示了 3.2/3 的意思。
如果您想提高自己的技术水平,欢迎加入本站官方1号QQ群:&&,&&2号QQ群:,在群里结识技术精英和交流技术^_^
本站联系邮箱:}

我要回帖

更多关于 linux运行tomcat 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信